diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..66c19214a7 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,84 @@ +name: build +on: + workflow_dispatch: + push: + branches: + - master + paths: + - "backend/package.json" + pull_request: + branches: + - master + paths: + - "backend/package.json" +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: "master" + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "20" + - name: Install dependencies + run: | + npm install -g pnpm + cd backend && pnpm i --no-frozen-lockfile + # - name: Test + # run: | + # cd backend + # pnpm test + # - name: Build + # run: | + # cd backend + # pnpm run build + - name: Bundle + run: | + cd backend + pnpm bundle:esbuild + - id: tag + name: Generate release tag + run: | + cd backend + SUBSTORE_RELEASE=`node --eval="process.stdout.write(require('./package.json').version)"` + echo "release_tag=$SUBSTORE_RELEASE" >> $GITHUB_OUTPUT + - name: Prepare release + run: | + cd backend + pnpm i -D conventional-changelog-cli + pnpm run changelog + - name: Release + uses: softprops/action-gh-release@v1 + if: ${{ success() }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + body_path: ./backend/CHANGELOG.md + tag_name: ${{ steps.tag.outputs.release_tag }} + # generate_release_notes: true + files: | + ./backend/sub-store.min.js + ./backend/dist/sub-store-0.min.js + ./backend/dist/sub-store-1.min.js + ./backend/dist/sub-store-parser.loon.min.js + ./backend/dist/cron-sync-artifacts.min.js + ./backend/dist/sub-store.bundle.js + - name: Git push assets to "release" branch + run: | + cd backend/dist || exit 1 + git init + git config --local user.name "github-actions[bot]" + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b release + git add . + git commit -m "release: ${{ steps.tag.outputs.release_tag }}" + git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" + git push -f -u origin release + # - name: Sync to GitLab + # env: + # GITLAB_PIPELINE_TOKEN: ${{ secrets.GITLAB_PIPELINE_TOKEN }} + # run: | + # curl -X POST --fail -F token=$GITLAB_PIPELINE_TOKEN -F ref=master https://gitlab.com/api/v4/projects/48891296/trigger/pipeline diff --git a/.gitignore b/.gitignore index 39695f6a31..1777dfddc6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store # json config sub-store.json root.json @@ -86,7 +87,7 @@ out # Nuxt.js build / generate output .nuxt -dist +# dist # Gatsby files .cache/ @@ -117,4 +118,20 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Dist files +backend/dist/* +!backend/dist/.gitkeep +backend/sub-store.min.js + +CHANGELOG.md diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index b58b603fea..0000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/MagicStore.iml b/.idea/MagicStore.iml deleted file mode 100644 index 24643cc374..0000000000 --- a/.idea/MagicStore.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dictionaries/pengym.xml b/.idea/dictionaries/pengym.xml deleted file mode 100644 index f54b023944..0000000000 --- a/.idea/dictionaries/pengym.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - obfs - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 3db675c4e8..0000000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 28a804d893..0000000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 8fe30fae48..0000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7f4c..0000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..885dfe40c7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,663 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (c) 2015 Ayuntamiento de Madrid + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md index 91a5e97c96..437da5cf81 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,75 @@ -# Sub-Store -> This project is still under active development. Current version: v0.1 (backend only). +
+
+Sub-Store +
+
+

Sub-Store

+

+ +

+Advanced Subscription Manager for QX, Loon, Surge, Stash, Egern and Shadowrocket. +

+ +[![Build](https://github.com/sub-store-org/Sub-Store/actions/workflows/main.yml/badge.svg)](https://github.com/sub-store-org/Sub-Store/actions/workflows/main.yml) ![GitHub](https://img.shields.io/github/license/sub-store-org/Sub-Store) ![GitHub issues](https://img.shields.io/github/issues/sub-store-org/Sub-Store) ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/Peng-Ym/Sub-Store) ![Lines of code](https://img.shields.io/tokei/lines/github/sub-store-org/Sub-Store) ![Size](https://img.shields.io/github/languages/code-size/sub-store-org/Sub-Store) +sub-store-org%2FSub-Store | Trendshift +[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/PengYM) + +Core functionalities: -Subscription manager for QX, Loon and Surge. -Core functionality: 1. Conversion among various formats. 2. Subscription formatting. -3. Collect multiple subscription in one URL. +3. Collect multiple subscriptions in one URL. + +> The following descriptions of features may not be updated in real-time. Please refer to the actual available features for accurate information. + ## 1. Subscription Conversion + ### Supported Input Formats -- [x] SS URI -- [x] SSR URI -- [x] V2RayN URI -- [x] QX (SS, SSR, VMess, Trojan, HTTP) -- [x] Loon (SS, SSR, VMess, Trojan, HTTP) -- [x] Surge (SS, VMess, Trojan, HTTP) + +> ⚠️ Do not use `Shadowrocket` or `NekoBox` to export URI and then import it as input. The URIs exported in this way may not be standard URIs. + +- [x] Proxy URI Scheme(`socks5`, `socks5+tls`, `http`, `https`(it's ok)) + + example: `socks5+tls://user:pass@ip:port#name` + +- [x] URI(AnyTLS, SOCKS, SS, SSR, VMess, VLESS, Trojan, Hysteria, Hysteria 2, TUIC v5, WireGuard) +- [x] Clash Proxies YAML +- [x] Clash Proxy JSON(single line) +- [x] QX (SS, SSR, VMess, Trojan, HTTP, SOCKS5, VLESS) +- [x] Loon (SS, SSR, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, WireGuard, VLESS, Hysteria 2) +- [x] Surge (Direct, SS, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, TUIC, Snell, Hysteria 2, SSH(Password authentication only), External Proxy Program(only for macOS), WireGuard(Surge to Surge)) +- [x] Surfboard (SS, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, WireGuard(Surfboard to Surfboard)) +- [x] Clash.Meta (Direct, SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria 2, TUIC, SSH, mieru, AnyTLS) +- [x] Stash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, TUIC, Juicity, SSH) + +Deprecated: + +- [x] Clash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard) ### Supported Target Platforms -- [x] QX -- [x] Loon + +- [x] Plain JSON +- [x] Stash +- [x] Clash.Meta(mihomo) +- [x] Surfboard - [x] Surge +- [x] SurgeMac(Use mihomo to support protocols that are not supported by Surge itself) +- [x] Loon +- [x] Egern +- [x] Shadowrocket +- [x] QX +- [x] sing-box +- [x] V2Ray +- [x] V2Ray URI + +Deprecated: + +- [x] Clash ## 2. Subscription Formatting + ### Filtering -- [x] **Keyword filter** -- [x] **Discard keywords filter** + - [x] **Regex filter** - [x] **Discard regex filter** - [x] **Region filter** @@ -32,13 +78,59 @@ Core functionality: - [x] **Script filter** ### Proxy Operations + - [x] **Set property operator**: set some proxy properties such as `udp`,`tfo`, `skip-cert-verify` etc. - [x] **Flag operator**: add flags or remove flags for proxies. - [x] **Sort operator**: sort proxies by name. -- [x] **Keyword sort operator**: sort proxies by keywords (fallback to normal sort). -- [x] **Keyword rename operator**: replace by keywords in proxy names. -- [x] **Keyword delete operator**: delete by keywords in proxy names. +- [x] **Regex sort operator**: sort proxies by keywords (fallback to normal sort). - [x] **Regex rename operator**: replace by regex in proxy names. - [x] **Regex delete operator**: delete by regex in proxy names. - [x] **Script operator**: modify proxy by script. +- [x] **Resolve Domain Operator**: resolve the domain of nodes to an IP address. + +### Development + +Install `pnpm` + +Go to `backend` directories, install node dependencies: + +``` +pnpm i +``` + +1. In `backend`, run the backend server on http://localhost:3000 + +babel(old school) + +``` +pnpm start +``` + +or + +esbuild(experimental) + +``` +SUB_STORE_BACKEND_API_PORT=3000 pnpm run --parallel "/^dev:.*/" +``` + +## LICENSE + +This project is under the GPL V3 LICENSE. + +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FPeng-YM%2FSub-Store.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FPeng-YM%2FSub-Store?ref=badge_large) + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=sub-store-org/sub-store&type=Date)](https://star-history.com/#sub-store-org/sub-store&Date) + +## Acknowledgements + +- Special thanks to @KOP-XIAO for his awesome resource-parser. Please give a [star](https://github.com/KOP-XIAO/QuantumultX) for his great work! +- Special thanks to @Orz-3 and @58xinian for their awesome icons. + +## Sponsors + +[![image](./support.nodeseek.com_page_promotion_id=8.png)](https://yxvm.com) +[NodeSupport](https://github.com/NodeSeekDev/NodeSupport) sponsored this project. diff --git a/backend/.babelrc b/backend/.babelrc new file mode 100644 index 0000000000..d45171f444 --- /dev/null +++ b/backend/.babelrc @@ -0,0 +1,27 @@ +{ + "presets": [ + [ + "@babel/preset-env" + ] + ], + "env": { + "test": { + "presets": [ + "@babel/preset-env" + ] + } + }, + "plugins": [ + [ + "babel-plugin-relative-path-import", + { + "paths": [ + { + "rootPathPrefix": "@", + "rootPathSuffix": "src" + } + ] + } + ] + ] +} \ No newline at end of file diff --git a/backend/.eslintrc.json b/backend/.eslintrc.json new file mode 100644 index 0000000000..919fea0ca9 --- /dev/null +++ b/backend/.eslintrc.json @@ -0,0 +1,15 @@ +{ + "ignorePatterns": ["*.min.js", "src/vendor/*.js"], + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + } +} diff --git a/backend/.prettierrc.json b/backend/.prettierrc.json new file mode 100644 index 0000000000..9848721705 --- /dev/null +++ b/backend/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "tabWidth": 4, + "bracketSpacing": true +} diff --git a/backend/banner b/backend/banner new file mode 100644 index 0000000000..6356592313 --- /dev/null +++ b/backend/banner @@ -0,0 +1,15 @@ +/** + * ███████╗██╗ ██╗██████╗ ███████╗████████╗ ██████╗ ██████╗ ███████╗ + * ██╔════╝██║ ██║██╔══██╗ ██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗██╔════╝ + * ███████╗██║ ██║██████╔╝█████╗███████╗ ██║ ██║ ██║██████╔╝█████╗ + * ╚════██║██║ ██║██╔══██╗╚════╝╚════██║ ██║ ██║ ██║██╔══██╗██╔══╝ + * ███████║╚██████╔╝██████╔╝ ███████║ ██║ ╚██████╔╝██║ ██║███████╗ + * ╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ + * Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket! + * @updated: <%= updated %> + * @version: <%= pkg.version %> + * @author: Peng-YM + * @github: https://github.com/sub-store-org/Sub-Store + * @documentation: https://www.notion.so/Sub-Store-6259586994d34c11a4ced5c406264b46 + */ + diff --git a/backend/bundle-esbuild.js b/backend/bundle-esbuild.js new file mode 100644 index 0000000000..05d6bd66c1 --- /dev/null +++ b/backend/bundle-esbuild.js @@ -0,0 +1,77 @@ +#!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); +const { build } = require('esbuild'); + +!(async () => { + const version = JSON.parse( + fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'), + ).version.trim(); + + const artifacts = [ + { src: 'src/main.js', dest: 'sub-store.min.js' }, + { + src: 'src/products/resource-parser.loon.js', + dest: 'dist/sub-store-parser.loon.min.js', + }, + { + src: 'src/products/cron-sync-artifacts.js', + dest: 'dist/cron-sync-artifacts.min.js', + }, + { src: 'src/products/sub-store-0.js', dest: 'dist/sub-store-0.min.js' }, + { src: 'src/products/sub-store-1.js', dest: 'dist/sub-store-1.min.js' }, + ]; + + for await (const artifact of artifacts) { + await build({ + entryPoints: [artifact.src], + bundle: true, + minify: true, + sourcemap: false, + platform: 'browser', + format: 'iife', + outfile: artifact.dest, + }); + } + + let content = fs.readFileSync(path.join(__dirname, 'sub-store.min.js'), { + encoding: 'utf8', + }); + content = content.replace( + /eval\(('|")(require\(('|").*?('|")\))('|")\)/g, + '$2', + ); + fs.writeFileSync( + path.join(__dirname, 'dist/sub-store.no-bundle.js'), + content, + { + encoding: 'utf8', + }, + ); + + await build({ + entryPoints: ['dist/sub-store.no-bundle.js'], + bundle: true, + minify: true, + sourcemap: false, + platform: 'node', + format: 'cjs', + outfile: 'dist/sub-store.bundle.js', + }); + fs.writeFileSync( + path.join(__dirname, 'dist/sub-store.bundle.js'), + `// SUB_STORE_BACKEND_VERSION: ${version} +${fs.readFileSync(path.join(__dirname, 'dist/sub-store.bundle.js'), { + encoding: 'utf8', +})}`, + { + encoding: 'utf8', + }, + ); +})() + .catch((e) => { + console.log(e); + }) + .finally(() => { + console.log('done'); + }); diff --git a/backend/bundle.js b/backend/bundle.js new file mode 100644 index 0000000000..e1961530e9 --- /dev/null +++ b/backend/bundle.js @@ -0,0 +1,51 @@ +#!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); +const { build } = require('esbuild'); + +!(async () => { + const version = JSON.parse( + fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'), + ).version.trim(); + + let content = fs.readFileSync(path.join(__dirname, 'sub-store.min.js'), { + encoding: 'utf8', + }); + content = content.replace( + /eval\(('|")(require\(('|").*?('|")\))('|")\)/g, + '$2', + ); + fs.writeFileSync( + path.join(__dirname, 'dist/sub-store.no-bundle.js'), + content, + { + encoding: 'utf8', + }, + ); + + await build({ + entryPoints: ['dist/sub-store.no-bundle.js'], + bundle: true, + minify: true, + sourcemap: true, + platform: 'node', + format: 'cjs', + outfile: 'dist/sub-store.bundle.js', + }); + fs.writeFileSync( + path.join(__dirname, 'dist/sub-store.bundle.js'), + `// SUB_STORE_BACKEND_VERSION: ${version} +${fs.readFileSync(path.join(__dirname, 'dist/sub-store.bundle.js'), { + encoding: 'utf8', +})}`, + { + encoding: 'utf8', + }, + ); +})() + .catch((e) => { + console.log(e); + }) + .finally(() => { + console.log('done'); + }); diff --git a/backend/dev-esbuild.js b/backend/dev-esbuild.js new file mode 100644 index 0000000000..dd44c57485 --- /dev/null +++ b/backend/dev-esbuild.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node +const { build } = require('esbuild'); + +!(async () => { + const artifacts = [{ src: 'src/main.js', dest: 'sub-store.min.js' }]; + + for await (const artifact of artifacts) { + await build({ + entryPoints: [artifact.src], + bundle: true, + minify: false, + sourcemap: false, + platform: 'node', + format: 'cjs', + outfile: artifact.dest, + }); + } +})() + .catch((e) => { + console.log(e); + }) + .finally(() => { + console.log('done'); + }); diff --git a/backend/dist/.gitkeep b/backend/dist/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/gulpfile.babel.js b/backend/gulpfile.babel.js new file mode 100644 index 0000000000..d865f71c9e --- /dev/null +++ b/backend/gulpfile.babel.js @@ -0,0 +1,118 @@ +import fs from 'fs'; +import browserify from 'browserify'; +import gulp from 'gulp'; +import prettier from 'gulp-prettier'; +import header from 'gulp-header'; +import eslint from 'gulp-eslint-new'; +import newFile from 'gulp-file'; +import path from 'path'; +import tap from 'gulp-tap'; + +import pkg from './package.json'; + +export function peggy() { + return gulp.src('src/**/*.peg').pipe( + tap(function (file) { + const filename = path.basename(file.path).split('.')[0] + '.js'; + const raw = fs.readFileSync(file.path, 'utf8'); + const contents = `import * as peggy from 'peggy'; +const grammars = String.raw\`\n${raw}\n\`; +let parser; +export default function getParser() { + if (!parser) { + parser = peggy.generate(grammars); + } + return parser; +}\n`; + return newFile(filename, contents).pipe( + gulp.dest(path.dirname(file.path)), + ); + }), + ); +} + +export function lint() { + return gulp + .src('src/**/*.js') + .pipe(eslint({ fix: true })) + .pipe(eslint.fix()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +} + +export function styles() { + return gulp + .src('src/**/*.js') + .pipe( + prettier({ + singleQuote: true, + trailingComma: 'all', + tabWidth: 4, + bracketSpacing: true, + }), + ) + .pipe(gulp.dest((file) => file.base)); +} + +function scripts(src, dest) { + return () => { + return browserify(src) + .transform('babelify', { + presets: [['@babel/preset-env']], + plugins: [ + [ + 'babel-plugin-relative-path-import', + { + paths: [ + { + rootPathPrefix: '@', + rootPathSuffix: 'src', + }, + ], + }, + ], + ], + }) + .plugin('tinyify') + .bundle() + .pipe(fs.createWriteStream(dest)); + }; +} + +function banner(dest) { + return () => + gulp + .src(dest) + .pipe( + header(fs.readFileSync('./banner', 'utf-8'), { + pkg, + updated: new Date().toLocaleString('zh-CN'), + }), + ) + .pipe(gulp.dest((file) => file.base)); +} + +const artifacts = [ + { src: 'src/main.js', dest: 'sub-store.min.js' }, + { + src: 'src/products/resource-parser.loon.js', + dest: 'dist/sub-store-parser.loon.min.js', + }, + { + src: 'src/products/cron-sync-artifacts.js', + dest: 'dist/cron-sync-artifacts.min.js', + }, + { src: 'src/products/sub-store-0.js', dest: 'dist/sub-store-0.min.js' }, + { src: 'src/products/sub-store-1.js', dest: 'dist/sub-store-1.min.js' }, +]; + +export const build = gulp.series( + gulp.parallel( + artifacts.map((artifact) => scripts(artifact.src, artifact.dest)), + ), + gulp.parallel(artifacts.map((artifact) => banner(artifact.dest))), +); + +const all = gulp.series(peggy, lint, styles, build); + +export default all; diff --git a/backend/jsconfig.json b/backend/jsconfig.json new file mode 100644 index 0000000000..df83de409a --- /dev/null +++ b/backend/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + } +} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index c5780687ec..273564f8b7 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,11 +1,75 @@ { - "name": "sub-store-backend", - "version": "0.0.1", - "description": "Advanced Subscription Manager for QX, Loon, and Surge.", - "main": "sub-store.js", + "name": "sub-store", + "version": "2.19.34", + "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.", + "main": "src/main.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "preinstall": "npx only-allow pnpm", + "test": "gulp peggy && npx cross-env BABEL_ENV=test mocha src/test/**/*.spec.js --require @babel/register --recursive", + "serve": "node sub-store.min.js", + "start": "nodemon -w src -w package.json --exec babel-node src/main.js", + "dev:esbuild": "nodemon -w src -w package.json dev-esbuild.js", + "dev:run": "nodemon -w sub-store.min.js sub-store.min.js", + "build": "gulp", + "bundle": "node bundle.js", + "bundle:esbuild": "node bundle-esbuild.js", + "changelog": "conventional-changelog -p cli -i CHANGELOG.md -s" }, - "author": "", - "license": "GPL" -} + "author": "Peng-YM", + "license": "GPL-3.0", + "pnpm": { + "patchedDependencies": { + "http-proxy@1.18.1": "patches/http-proxy@1.18.1.patch" + } + }, + "dependencies": { + "@maxmind/geoip2-node": "^5.0.0", + "automerge": "1.0.1-preview.7", + "body-parser": "^1.19.0", + "buffer": "^6.0.3", + "dotenv": "^16.4.7", + "connect-history-api-fallback": "^2.0.0", + "cron": "^3.1.6", + "dns-packet": "^5.6.1", + "express": "^4.17.1", + "mime-types": "^2.1.35", + "http-proxy-middleware": "^3.0.3", + "ip-address": "^9.0.5", + "js-base64": "^3.7.2", + "jsrsasign": "^11.1.0", + "lodash": "^4.17.21", + "ms": "^2.1.3", + "nanoid": "^3.3.3", + "semver": "^7.6.3", + "static-js-yaml": "^1.0.0", + "undici": "^7.4.0" + }, + "devDependencies": { + "@babel/core": "^7.18.0", + "@babel/node": "^7.17.10", + "@babel/preset-env": "^7.18.0", + "@babel/register": "^7.17.7", + "@types/gulp": "^4.0.9", + "axios": "^0.21.2", + "babel-plugin-relative-path-import": "^2.0.1", + "babelify": "^10.0.0", + "browser-pack-flat": "^3.4.2", + "browserify": "^17.0.0", + "chai": "^4.3.6", + "esbuild": "^0.19.8", + "eslint": "^8.16.0", + "gulp": "^4.0.2", + "gulp-babel": "^8.0.0", + "gulp-eslint-new": "^1.4.4", + "gulp-file": "^0.4.0", + "gulp-header": "^2.0.9", + "gulp-prettier": "^4.0.0", + "gulp-tap": "^2.0.0", + "mocha": "^10.0.0", + "nodemon": "^2.0.16", + "peggy": "^2.0.1", + "prettier": "2.6.2", + "prettier-plugin-sort-imports": "^1.6.1", + "tinyify": "^3.0.0" + } +} \ No newline at end of file diff --git a/backend/patches/http-proxy@1.18.1.patch b/backend/patches/http-proxy@1.18.1.patch new file mode 100644 index 0000000000..04e1791370 --- /dev/null +++ b/backend/patches/http-proxy@1.18.1.patch @@ -0,0 +1,46 @@ +diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js +index 6513e81d80d5250ea249ea833f819ece67897c7e..486d4c896d65a3bb7cf63307af68facb3ddb886b 100644 +--- a/lib/http-proxy/common.js ++++ b/lib/http-proxy/common.js +@@ -1,6 +1,5 @@ + var common = exports, + url = require('url'), +- extend = require('util')._extend, + required = require('requires-port'); + + var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i, +@@ -40,10 +39,10 @@ common.setupOutgoing = function(outgoing, options, req, forward) { + ); + + outgoing.method = options.method || req.method; +- outgoing.headers = extend({}, req.headers); ++ outgoing.headers = Object.assign({}, req.headers); + + if (options.headers){ +- extend(outgoing.headers, options.headers); ++ Object.assign(outgoing.headers, options.headers); + } + + if (options.auth) { +diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js +index 977a4b3622b9eaac27689f06347ea4c5173a96cd..88b2d0fcfa03c3aafa47c7e6d38e64412c45a7cc 100644 +--- a/lib/http-proxy/index.js ++++ b/lib/http-proxy/index.js +@@ -1,5 +1,4 @@ + var httpProxy = module.exports, +- extend = require('util')._extend, + parse_url = require('url').parse, + EE3 = require('eventemitter3'), + http = require('http'), +@@ -47,9 +46,9 @@ function createRightProxy(type) { + args[cntr] !== res + ) { + //Copy global options +- requestOptions = extend({}, options); ++ requestOptions = Object.assign({}, options); + //Overwrite with request options +- extend(requestOptions, args[cntr]); ++ Object.assign(requestOptions, args[cntr]); + + cntr--; + } diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml new file mode 100644 index 0000000000..dec8b5d9e5 --- /dev/null +++ b/backend/pnpm-lock.yaml @@ -0,0 +1,9206 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +patchedDependencies: + http-proxy@1.18.1: + hash: 8071c23044f455271f4d4074ae4c7b81beec17a03aefd158d5f4edd4ef751c11 + path: patches/http-proxy@1.18.1.patch + +importers: + + .: + dependencies: + '@maxmind/geoip2-node': + specifier: ^5.0.0 + version: 5.0.0 + automerge: + specifier: 1.0.1-preview.7 + version: 1.0.1-preview.7 + body-parser: + specifier: ^1.19.0 + version: 1.20.3 + buffer: + specifier: ^6.0.3 + version: 6.0.3 + connect-history-api-fallback: + specifier: ^2.0.0 + version: 2.0.0 + cron: + specifier: ^3.1.6 + version: 3.5.0 + dns-packet: + specifier: ^5.6.1 + version: 5.6.1 + express: + specifier: ^4.17.1 + version: 4.21.2 + http-proxy-middleware: + specifier: ^3.0.3 + version: 3.0.3 + ip-address: + specifier: ^9.0.5 + version: 9.0.5 + js-base64: + specifier: ^3.7.2 + version: 3.7.7 + jsrsasign: + specifier: ^11.1.0 + version: 11.1.0 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + ms: + specifier: ^2.1.3 + version: 2.1.3 + nanoid: + specifier: ^3.3.3 + version: 3.3.8 + semver: + specifier: ^7.6.3 + version: 7.6.3 + static-js-yaml: + specifier: ^1.0.0 + version: 1.0.0 + undici: + specifier: ^7.4.0 + version: 7.4.0 + devDependencies: + '@babel/core': + specifier: ^7.18.0 + version: 7.26.0 + '@babel/node': + specifier: ^7.17.10 + version: 7.26.0(@babel/core@7.26.0) + '@babel/preset-env': + specifier: ^7.18.0 + version: 7.26.0(@babel/core@7.26.0) + '@babel/register': + specifier: ^7.17.7 + version: 7.25.9(@babel/core@7.26.0) + '@types/gulp': + specifier: ^4.0.9 + version: 4.0.17 + axios: + specifier: ^0.21.2 + version: 0.21.4 + babel-plugin-relative-path-import: + specifier: ^2.0.1 + version: 2.0.1 + babelify: + specifier: ^10.0.0 + version: 10.0.0(@babel/core@7.26.0) + browser-pack-flat: + specifier: ^3.4.2 + version: 3.5.0 + browserify: + specifier: ^17.0.0 + version: 17.0.1 + chai: + specifier: ^4.3.6 + version: 4.5.0 + esbuild: + specifier: ^0.19.8 + version: 0.19.12 + eslint: + specifier: ^8.16.0 + version: 8.57.1 + gulp: + specifier: ^4.0.2 + version: 4.0.2 + gulp-babel: + specifier: ^8.0.0 + version: 8.0.0(@babel/core@7.26.0) + gulp-eslint-new: + specifier: ^1.4.4 + version: 1.9.1 + gulp-file: + specifier: ^0.4.0 + version: 0.4.0 + gulp-header: + specifier: ^2.0.9 + version: 2.0.9 + gulp-prettier: + specifier: ^4.0.0 + version: 4.0.0 + gulp-tap: + specifier: ^2.0.0 + version: 2.0.0 + mocha: + specifier: ^10.0.0 + version: 10.8.2 + nodemon: + specifier: ^2.0.16 + version: 2.0.22 + peggy: + specifier: ^2.0.1 + version: 2.0.1 + prettier: + specifier: 2.6.2 + version: 2.6.2 + prettier-plugin-sort-imports: + specifier: ^1.6.1 + version: 1.8.6(typescript@5.7.3) + tinyify: + specifier: ^3.0.0 + version: 3.1.0 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.5': + resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.26.5': + resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.26.5': + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.25.9': + resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.26.3': + resolution: {integrity: sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.3': + resolution: {integrity: sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.26.5': + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.25.9': + resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.26.5': + resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.25.9': + resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + + '@babel/node@7.26.0': + resolution: {integrity: sha512-5ASMjh42hbnqyCOK68Q5chh1jKAqn91IswFTN+niwt4FLABhEWCT1tEuuo6mlNQ4WG/oFQLvJ71PaHAKtWtJyA==} + engines: {node: '>=6.9.0'} + hasBin: true + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/parser@7.26.5': + resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': + resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9': + resolution: {integrity: sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9': + resolution: {integrity: sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9': + resolution: {integrity: sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9': + resolution: {integrity: sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.26.0': + resolution: {integrity: sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.25.9': + resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.25.9': + resolution: {integrity: sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.25.9': + resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.26.5': + resolution: {integrity: sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.25.9': + resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.25.9': + resolution: {integrity: sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.26.0': + resolution: {integrity: sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.25.9': + resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.25.9': + resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.25.9': + resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.25.9': + resolution: {integrity: sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.25.9': + resolution: {integrity: sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.25.9': + resolution: {integrity: sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.26.3': + resolution: {integrity: sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.25.9': + resolution: {integrity: sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.25.9': + resolution: {integrity: sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.25.9': + resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.25.9': + resolution: {integrity: sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.25.9': + resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.25.9': + resolution: {integrity: sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.25.9': + resolution: {integrity: sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.25.9': + resolution: {integrity: sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.26.3': + resolution: {integrity: sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-systemjs@7.25.9': + resolution: {integrity: sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.25.9': + resolution: {integrity: sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.25.9': + resolution: {integrity: sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.26.5': + resolution: {integrity: sha512-OHqczNm4NTQlW1ghrVY43FPoiRzbmzNVbcgVnMKZN/RQYezHUSdjACjaX50CD3B7UIAjv39+MlsrVDb3v741FA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.25.9': + resolution: {integrity: sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.25.9': + resolution: {integrity: sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.25.9': + resolution: {integrity: sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.25.9': + resolution: {integrity: sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.25.9': + resolution: {integrity: sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.25.9': + resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.25.9': + resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.25.9': + resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.25.9': + resolution: {integrity: sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.25.9': + resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.26.0': + resolution: {integrity: sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.25.9': + resolution: {integrity: sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.25.9': + resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.25.9': + resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.25.9': + resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.25.9': + resolution: {integrity: sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.25.9': + resolution: {integrity: sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.25.9': + resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.25.9': + resolution: {integrity: sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.25.9': + resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.25.9': + resolution: {integrity: sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.26.0': + resolution: {integrity: sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + '@babel/register@7.25.9': + resolution: {integrity: sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.26.0': + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.26.5': + resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.26.5': + resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.19.12': + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.19.12': + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.19.12': + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.19.12': + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.19.12': + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.19.12': + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.19.12': + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.19.12': + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.19.12': + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.19.12': + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.19.12': + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.19.12': + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.19.12': + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.19.12': + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.19.12': + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.19.12': + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.19.12': + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.19.12': + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.19.12': + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.19.12': + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.19.12': + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.19.12': + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.19.12': + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@goto-bus-stop/common-shake@2.4.1': + resolution: {integrity: sha512-U77x9X3VXHQfuo8ncsQShFGnQ+DLSiHjaAKWyqyfIzcoddnOromP2SE615r1UmZdZTyc9DAZ4BYEBs2QQ1JwMQ==} + + '@goto-bus-stop/envify@5.0.0': + resolution: {integrity: sha512-xAnxuDWmwQxO8CgVuPTxKuNsKDfwyXXTyAabG4sNoK59H/ZMC7BHxTA/4ehtinsxbcH7/9L65F5VhyNdQfUyqA==} + hasBin: true + + '@gulpjs/to-absolute-glob@4.0.0': + resolution: {integrity: sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==} + engines: {node: '>=10.13.0'} + + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@leichtgewicht/ip-codec@2.0.5': + resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} + + '@maxmind/geoip2-node@5.0.0': + resolution: {integrity: sha512-ki+q5//oU4tZ3BAhegZJcB5czoZyic5JSTEKbrUAQB/BzAoAiGyLW0immEmQvVVyy2SMlvBTJ3zqyRj8K9BbwQ==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@types/eslint@8.56.12': + resolution: {integrity: sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/expect@1.20.4': + resolution: {integrity: sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==} + + '@types/glob-stream@8.0.2': + resolution: {integrity: sha512-kyuRfGE+yiSJWzSO3t74rXxdZNdYfLcllO0IUha4eX1fl40pm9L02Q/TEc3mykTLjoWz4STBNwYnUWdFu3I0DA==} + + '@types/gulp@4.0.17': + resolution: {integrity: sha512-+pKQynu2C/HS16kgmDlAicjtFYP8kaa86eE9P0Ae7GB5W29we/E2TIdbOWtEZD5XkpY+jr8fyqfwO6SWZecLpQ==} + + '@types/http-proxy@1.17.15': + resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/luxon@3.4.2': + resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} + + '@types/node@22.10.5': + resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + + '@types/picomatch@3.0.1': + resolution: {integrity: sha512-1MRgzpzY0hOp9pW/kLRxeQhUWwil6gnrUYd3oEpeYBqp/FexhaCPv3F8LsYr47gtUU45fO2cm1dbwkSrHEo8Uw==} + + '@types/streamx@2.9.5': + resolution: {integrity: sha512-IHYsa6jYrck8VEdSwpY141FTTf6D7boPeMq9jy4qazNrFMA4VbRz/sw5LSsfR7jwdDcx0QKWkUexZvsWBC2eIQ==} + + '@types/undertaker-registry@1.0.4': + resolution: {integrity: sha512-tW77pHh2TU4uebWXWeEM5laiw8BuJ7pyJYDh6xenOs75nhny2kVgwYbegJ4BoLMYsIrXaBpKYaPdYO3/udG+hg==} + + '@types/undertaker@1.2.11': + resolution: {integrity: sha512-j1Z0V2ByRHr8ZK7eOeGq0LGkkdthNFW0uAZGY22iRkNQNL9/vAV0yFPr1QN3FM/peY5bxs9P+1f0PYJTQVa5iA==} + + '@types/vinyl-fs@3.0.5': + resolution: {integrity: sha512-ckYz9giHgV6U10RFuf9WsDQ3X86EFougapxHmmoxLK7e6ICQqO8CE+4V/3lBN148V5N1pb4nQMmMjyScleVsig==} + + '@types/vinyl@2.0.12': + resolution: {integrity: sha512-Sr2fYMBUVGYq8kj3UthXFAu5UN6ZW+rYr4NACjZQJvHvj+c8lYv0CahmZ2P/r7iUkN44gGUBwqxZkrKXYPb7cw==} + + '@ungap/structured-clone@1.2.1': + resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-node@1.8.2: + resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} + + acorn-node@2.0.1: + resolution: {integrity: sha512-VLR5sHqjk+8c5hrKeP2fWaIHb8eewsoxnZ8r2qpwRHXMHuC7KyOPflnOx9dLssVQUurzJ7rO0OzIFjHcndafWw==} + + acorn-walk@7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + + acorn@5.7.4: + resolution: {integrity: sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + amdefine@1.0.1: + resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} + engines: {node: '>=0.4.2'} + + ansi-colors@1.1.0: + resolution: {integrity: sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==} + engines: {node: '>=0.10.0'} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-gray@0.1.1: + resolution: {integrity: sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==} + engines: {node: '>=0.10.0'} + + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@2.2.1: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} + engines: {node: '>=0.10.0'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-wrap@0.1.0: + resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==} + engines: {node: '>=0.10.0'} + + anymatch@2.0.0: + resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + append-buffer@1.0.2: + resolution: {integrity: sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==} + engines: {node: '>=0.10.0'} + + archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + arr-diff@4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} + + arr-filter@1.1.2: + resolution: {integrity: sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==} + engines: {node: '>=0.10.0'} + + arr-flatten@1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + + arr-map@2.0.2: + resolution: {integrity: sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==} + engines: {node: '>=0.10.0'} + + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-each@1.0.1: + resolution: {integrity: sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==} + engines: {node: '>=0.10.0'} + + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + array-from@2.1.1: + resolution: {integrity: sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==} + + array-initial@1.1.0: + resolution: {integrity: sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==} + engines: {node: '>=0.10.0'} + + array-last@1.3.0: + resolution: {integrity: sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==} + engines: {node: '>=0.10.0'} + + array-slice@1.1.0: + resolution: {integrity: sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==} + engines: {node: '>=0.10.0'} + + array-sort@1.0.0: + resolution: {integrity: sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==} + engines: {node: '>=0.10.0'} + + array-unique@0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + + array.prototype.reduce@1.0.7: + resolution: {integrity: sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + assert@1.5.1: + resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} + + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + + assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + + async-done@1.3.2: + resolution: {integrity: sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==} + engines: {node: '>= 0.10'} + + async-each@1.0.6: + resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} + + async-settle@1.0.0: + resolution: {integrity: sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==} + engines: {node: '>= 0.10'} + + atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + + automerge@1.0.1-preview.7: + resolution: {integrity: sha512-Fz5fJdU59xYYj0viteMKTGg/bQWTyibZlkY3V8VQqx9Do1Eg3jtud2+BAI5ZQiKwdWocXc4KKC5o5vT1dzouag==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios@0.21.4: + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + + babel-plugin-polyfill-corejs2@0.4.12: + resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.10.6: + resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.3: + resolution: {integrity: sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-relative-path-import@2.0.1: + resolution: {integrity: sha512-jOtB/Lef7QFNAEGRV4VmUvP/VsizpvOVonrTeTTE8TxVIR0FL/wJTzFQp4ei5Jf5+EWklFORmnsXOjLxvNVeRg==} + + babelify@10.0.0: + resolution: {integrity: sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + bach@1.2.0: + resolution: {integrity: sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==} + engines: {node: '>= 0.10'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bare-events@2.5.4: + resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + base@0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + + binary-extensions@1.13.1: + resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} + engines: {node: '>=0.10.0'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@5.1.0: + resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} + + bn.js@4.12.1: + resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browser-pack-flat@3.5.0: + resolution: {integrity: sha512-u3iJUjs+TC/NGIL2GLyIcn5ppoNZXhTWqSW/gQbGIGvQiXXCQQzr5VWfACFraXQn2JrDlyRnKLeOs5AWXzKI6A==} + hasBin: true + + browser-pack@6.1.0: + resolution: {integrity: sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==} + hasBin: true + + browser-process-hrtime@0.1.3: + resolution: {integrity: sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==} + + browser-resolve@2.0.0: + resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + browser-unpack@1.4.3: + resolution: {integrity: sha512-vWNnNr19gS3RR76/Xrz2xFUUFumVu7tt0XRV1wikjDAmujGgz8Ly0J8CSOMoQP9JCZ/QGiOnhval6wLkctYALQ==} + hasBin: true + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + + browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + + browserify-rsa@4.1.1: + resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} + engines: {node: '>= 0.10'} + + browserify-sign@4.2.3: + resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} + engines: {node: '>= 0.12'} + + browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + + browserify@17.0.1: + resolution: {integrity: sha512-pxhT00W3ylMhCHwG5yfqtZjNnFuX5h2IJdaBfSo4ChaaBsIp9VLrEMQ1bHV+Xr1uLPXuNDDM1GlJkjli0qkRsw==} + engines: {node: '>= 0.8'} + hasBin: true + + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-equal@1.0.1: + resolution: {integrity: sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==} + engines: {node: '>=0.4'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + buffer@5.2.1: + resolution: {integrity: sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + + bundle-collapser@1.4.0: + resolution: {integrity: sha512-Gd3K3+3KI1Utuk+gwAvuOVOjT/2XLGL8tU6FwDKk04LlOZkYfT0pwQllsG1Dv8RRhgcjNxZSDmmSXb0AOkwSwg==} + hasBin: true + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cache-base@1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + + cached-path-relative@1.1.0: + resolution: {integrity: sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==} + + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + + call-matcher@2.0.0: + resolution: {integrity: sha512-CIDC5wZZfZ2VjZu849WQckS58Z3pJXFfRaSjNjgo/q3in5zxkhTwVL83vttgtmvyLG7TuDlLlBya7SKP6CjDIA==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@3.0.0: + resolution: {integrity: sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==} + engines: {node: '>=0.10.0'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001692: + resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==} + + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + engines: {node: '>=4'} + + chalk@1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + chokidar@2.1.8: + resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + cipher-base@1.0.6: + resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} + engines: {node: '>= 0.10'} + + class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + + cliui@3.2.0: + resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + clone-buffer@1.0.0: + resolution: {integrity: sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==} + engines: {node: '>= 0.10'} + + clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + + clone-stats@1.0.0: + resolution: {integrity: sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==} + + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + + cloneable-readable@1.1.3: + resolution: {integrity: sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==} + + code-point-at@1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + + collection-map@1.0.0: + resolution: {integrity: sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==} + engines: {node: '>=0.10.0'} + + collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + + combine-source-map@0.8.0: + resolution: {integrity: sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + common-shakeify@1.1.2: + resolution: {integrity: sha512-r2zRKPCbCx1l9BT8nVGZssZXrH9jeLl5qfHKxUwSBT7Kr9l1jSjZsItZE/jXo+GYDyO3kQfsyV7Poid475MgWQ==} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + + concat-stream@2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + + concat-with-sourcemaps@1.1.0: + resolution: {integrity: sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==} + + connect-history-api-fallback@2.0.0: + resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} + engines: {node: '>=0.8'} + + console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + + constants-browserify@1.0.0: + resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@1.1.3: + resolution: {integrity: sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + copy-descriptor@0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + + copy-props@2.0.5: + resolution: {integrity: sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==} + + core-js-compat@3.40.0: + resolution: {integrity: sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==} + + core-js@3.40.0: + resolution: {integrity: sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==} + + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + count-lines@0.1.2: + resolution: {integrity: sha512-YS8P4UYXX/hrDyLU3r/A5OcCNwdNbJFJckbe8j+x2Jhxsr2J4/rYl0sDwOljLZL7Uxc4s7mRSNcQD8dSjobz+g==} + engines: {node: '>=0.10.0'} + + create-ecdh@4.0.4: + resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + + cron@3.5.0: + resolution: {integrity: sha512-0eYZqCnapmxYcV06uktql93wNWdlTmmBFP2iYz+JPVcQqlyFYcn1lFuIk4R54pkOmE7mcldTAPZv6X5XA4Q46A==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crypto-browserify@3.12.1: + resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} + engines: {node: '>= 0.10'} + + d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} + + dash-ast@1.0.0: + resolution: {integrity: sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==} + + dash-ast@2.0.1: + resolution: {integrity: sha512-5TXltWJGc+RdnabUGzhRae1TRq6m4gr+3K2wQX0is5/F2yS6MJXJvLyI3ErAnsAXuJoGqvfVD5icRgim07DrxQ==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + dedent@0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + engines: {node: '>=6'} + + deep-equal@1.1.2: + resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==} + engines: {node: '>= 0.4'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + default-compare@1.0.0: + resolution: {integrity: sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==} + engines: {node: '>=0.10.0'} + + default-resolution@2.0.0: + resolution: {integrity: sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==} + engines: {node: '>= 0.10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + + define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + + define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + + defined@1.0.1: + resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + deps-sort@2.0.1: + resolution: {integrity: sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==} + hasBin: true + + des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detect-file@1.0.0: + resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} + engines: {node: '>=0.10.0'} + + detective@5.2.1: + resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} + engines: {node: '>=0.8.0'} + hasBin: true + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + + dns-packet@5.6.1: + resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} + engines: {node: '>=6'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + domain-browser@1.2.0: + resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==} + engines: {node: '>=0.4', npm: '>=1.2'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer2@0.0.2: + resolution: {integrity: sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==} + + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + duplexify@3.7.1: + resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + + duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + + each-props@1.3.2: + resolution: {integrity: sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.80: + resolution: {integrity: sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==} + + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + engines: {node: '>= 0.4'} + + es-array-method-boxes-properly@1.0.0: + resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + es5-ext@0.10.64: + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} + engines: {node: '>=0.10'} + + es6-iterator@2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + + es6-map@0.1.5: + resolution: {integrity: sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==} + + es6-set@0.1.6: + resolution: {integrity: sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==} + engines: {node: '>=0.12'} + + es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} + + es6-weak-map@2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + + esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escodegen@0.0.28: + resolution: {integrity: sha512-6ioQhg16lFs5c7XJlJFXIDxBjO4yRvXC9yK6dLNNGuhI3a/fJukHanPF6qtpjGDgAFzI8Wuq3PSIarWmaOq/5A==} + engines: {node: '>=0.4.0'} + hasBin: true + + escodegen@1.14.3: + resolution: {integrity: sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==} + engines: {node: '>=4.0'} + hasBin: true + + escodegen@1.3.3: + resolution: {integrity: sha512-z9FWgKc48wjMlpzF5ymKS1AF8OIgnKLp9VyN7KbdtyrP/9lndwUFqCtMm+TAJmJf7KJFFYc4cFJfVTTGkKEwsA==} + engines: {node: '>=0.10.0'} + hasBin: true + + escope@3.6.0: + resolution: {integrity: sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==} + engines: {node: '>=0.4.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + esniff@2.0.1: + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} + engines: {node: '>=0.10'} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@1.0.4: + resolution: {integrity: sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==} + engines: {node: '>=0.4.0'} + hasBin: true + + esprima@1.1.1: + resolution: {integrity: sha512-qxxB994/7NtERxgXdFgLHIs9M6bhLXc6qtUmWZ3L8+gTQ9qaoyki2887P2IqAYsoENyr8SUbTutStDniOHSDHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + espurify@2.1.1: + resolution: {integrity: sha512-zttWvnkhcDyGOhSH4vO2qCBILpdCMv/MX8lp4cqgRkQoDRGK2oZxi2GfWhlP2dIXmk7BaKeOTuzbHhyC68o8XQ==} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@1.3.2: + resolution: {integrity: sha512-OkbCPVUu8D9tbsLcUR+CKFRBbhZlogmkbWaP3BPERlkqzWL5Q6IdTz6eUk+b5cid2MTaCqJb2nNRGoJ8TpfPrg==} + engines: {node: '>=0.4.0'} + + estraverse@1.5.1: + resolution: {integrity: sha512-FpCjJDfmo3vsc/1zKSeqR5k42tcIhxFIlvq+h9j0fO2q/h2uLKyweq7rYJ+0CoVvrGQOxIS5wyBrW/+vF58BUQ==} + engines: {node: '>=0.4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-is-function@1.0.0: + resolution: {integrity: sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA==} + + estree-is-identifier@1.0.0: + resolution: {integrity: sha512-2BDRGrkQJV/NhCAmmE33A35WAaxq3WQaGHgQuD//7orGWfpFqj8Srkwvx0TH+20yIdOF1yMQwi8anv5ISec2AQ==} + + estree-is-member-expression@1.0.0: + resolution: {integrity: sha512-Ec+X44CapIGExvSZN+pGkmr5p7HwUVQoPQSd458Lqwvaf4/61k/invHSh4BYK8OXnCkfEhWuIoG5hayKLQStIg==} + + estree-is-require@1.0.0: + resolution: {integrity: sha512-oWxQdSEmnUwNZsDQYiBNpVxKEhMmsJQSSxnDrwsr1MWtooCLfhgzsNGzmokdmfK0EzEIS5V4LPvqxv1Kmb1vvA==} + + esutils@1.0.0: + resolution: {integrity: sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==} + engines: {node: '>=0.10.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-emitter@0.3.5: + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + + expand-brackets@2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + + expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + engines: {node: '>= 0.10.0'} + + ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + + extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + + falafel@2.2.5: + resolution: {integrity: sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==} + engines: {node: '>=0.4.0'} + + fancy-log@1.3.3: + resolution: {integrity: sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==} + engines: {node: '>= 0.10'} + + fancy-log@2.0.0: + resolution: {integrity: sha512-9CzxZbACXMUXW13tS0tI8XsGGmxWzO2DmYrGuBJOJ8k8q2K7hwfJA5qHjuPPe8wtsco33YR9wc+Rlr5wYFvhSA==} + engines: {node: '>=10.13.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@1.1.4: + resolution: {integrity: sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-sha256@1.3.0: + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + + find-cache-dir@2.1.0: + resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} + engines: {node: '>=6'} + + find-up@1.1.2: + resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==} + engines: {node: '>=0.10.0'} + + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + findup-sync@2.0.0: + resolution: {integrity: sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==} + engines: {node: '>= 0.10'} + + findup-sync@3.0.0: + resolution: {integrity: sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==} + engines: {node: '>= 0.10'} + + fined@1.2.0: + resolution: {integrity: sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==} + engines: {node: '>= 0.10'} + + flagged-respawn@1.0.1: + resolution: {integrity: sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==} + engines: {node: '>= 0.10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + + flush-write-stream@1.1.1: + resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + + for-own@1.0.0: + resolution: {integrity: sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==} + engines: {node: '>=0.10.0'} + + fork-stream@0.0.4: + resolution: {integrity: sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + from2-string@1.1.0: + resolution: {integrity: sha512-m8vCh+KnXXXBtfF2VUbiYlQ+nczLcntB0BrtNgpmLkHylhObe9WF1b2LZjBBzrZzA6P4mkEla6ZYQoOUTG8cYA==} + + from2@2.3.0: + resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + + fs-mkdirp-stream@1.0.0: + resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==} + engines: {node: '>= 0.10'} + + fs-mkdirp-stream@2.0.1: + resolution: {integrity: sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==} + engines: {node: '>=10.13.0'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@1.2.13: + resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} + engines: {node: '>= 4.0'} + os: [darwin] + deprecated: Upgrade to fsevents v2 to mitigate potential security issues + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-assigned-identifiers@1.2.0: + resolution: {integrity: sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==} + + get-caller-file@1.0.3: + resolution: {integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + + glob-parent@3.1.0: + resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-stream@6.1.0: + resolution: {integrity: sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==} + engines: {node: '>= 0.10'} + + glob-stream@8.0.2: + resolution: {integrity: sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==} + engines: {node: '>=10.13.0'} + + glob-watcher@5.0.5: + resolution: {integrity: sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==} + engines: {node: '>= 0.10'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + + global-modules@1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + + global-prefix@1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + glogg@1.0.2: + resolution: {integrity: sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==} + engines: {node: '>= 0.10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + gulp-babel@8.0.0: + resolution: {integrity: sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==} + engines: {node: '>=6'} + peerDependencies: + '@babel/core': ^7.0.0 + + gulp-cli@2.3.0: + resolution: {integrity: sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==} + engines: {node: '>= 0.10'} + hasBin: true + + gulp-eslint-new@1.9.1: + resolution: {integrity: sha512-ohcH/DJdLPNAq76SxZux2Ptah515Cvinnfze30yj19VoCqgsT6VH3BdNfll8XJGB8BLz1YWipZ5i45dxrNOk3w==} + engines: {node: ^12.20 || ^14.13 || >=16} + + gulp-file@0.4.0: + resolution: {integrity: sha512-3NPCJpAPpbNoV2aml8T96OK3Aof4pm4PMOIa1jSQbMNSNUUXdZ5QjVgLXLStjv0gg9URcETc7kvYnzXdYXUWug==} + + gulp-header@2.0.9: + resolution: {integrity: sha512-LMGiBx+qH8giwrOuuZXSGvswcIUh0OiioNkUpLhNyvaC6/Ga8X6cfAeme2L5PqsbXMhL8o8b/OmVqIQdxprhcQ==} + + gulp-prettier@4.0.0: + resolution: {integrity: sha512-REx99tBRRKJD7qLPaKpplReM9cq2vFvqhMbcUZtJEVjxGjb5Ji+gN9vi8bsM8UhnDV+l0Zrf5x6L4uZiDmvGFQ==} + engines: {node: '>=12'} + + gulp-tap@2.0.0: + resolution: {integrity: sha512-U5/v1bTozx672QHzrvzPe6fPl2io7Wqyrx2y30AG53eMU/idH4BrY/b2yikOkdyhjDqGgPoMUMnpBg9e9LK8Nw==} + + gulp@4.0.2: + resolution: {integrity: sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==} + engines: {node: '>= 0.10'} + hasBin: true + + gulplog@1.0.0: + resolution: {integrity: sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==} + engines: {node: '>= 0.10'} + + has-ansi@2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + + has-value@1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + + has-values@0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + + has-values@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + + has@1.0.4: + resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} + engines: {node: '>= 0.4.0'} + + hash-base@3.0.5: + resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} + engines: {node: '>= 0.10'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + htmlescape@1.1.1: + resolution: {integrity: sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==} + engines: {node: '>=0.10'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http-proxy-middleware@3.0.3: + resolution: {integrity: sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + http-proxy@1.18.1: + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + + https-browserify@1.0.0: + resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {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. + + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + inline-source-map@0.6.3: + resolution: {integrity: sha512-1aVsPEsJWMJq/pdMU61CDlm1URcW702MTB4w9/zUjMus6H/Py8o7g68Pr9D4I6QluWGt/KdmswuRhaA05xVR1w==} + + insert-module-globals@7.2.1: + resolution: {integrity: sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==} + hasBin: true + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + + invert-kv@1.0.0: + resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} + engines: {node: '>=0.10.0'} + + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + + ip6addr@0.2.5: + resolution: {integrity: sha512-9RGGSB6Zc9Ox5DpDGFnJdIeF0AsqXzdH+FspCfPPaU/L/4tI6P+5lIoFUFm9JXs9IrJv1boqAaNCQmoDADTSKQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-absolute@1.0.0: + resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} + engines: {node: '>=0.10.0'} + + is-accessor-descriptor@1.0.1: + resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} + engines: {node: '>= 0.10'} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.1.0: + resolution: {integrity: sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@1.0.1: + resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} + engines: {node: '>=0.10.0'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.1: + resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} + engines: {node: '>= 0.4'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-descriptor@1.0.1: + resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-descriptor@0.1.7: + resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} + engines: {node: '>= 0.4'} + + is-descriptor@1.0.3: + resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} + engines: {node: '>= 0.4'} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + + is-glob@3.1.0: + resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negated-glob@1.0.0: + resolution: {integrity: sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==} + engines: {node: '>=0.10.0'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + + is-number@4.0.0: + resolution: {integrity: sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-relative@1.0.0: + resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==} + engines: {node: '>=0.10.0'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-unc-path@1.0.0: + resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} + engines: {node: '>=0.10.0'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-utf8@0.2.1: + resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} + + is-valid-glob@1.0.0: + resolution: {integrity: sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==} + engines: {node: '>=0.10.0'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.0: + resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + isarray@0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isobject@2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + jsprim@2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + + jsrsasign@11.1.0: + resolution: {integrity: sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg==} + + just-debounce@1.1.0: + resolution: {integrity: sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + + kind-of@5.1.0: + resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==} + engines: {node: '>=0.10.0'} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + labeled-stream-splicer@2.0.2: + resolution: {integrity: sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==} + + last-run@1.1.1: + resolution: {integrity: sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==} + engines: {node: '>= 0.10'} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + lcid@1.0.0: + resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} + engines: {node: '>=0.10.0'} + + lead@1.0.0: + resolution: {integrity: sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==} + engines: {node: '>= 0.10'} + + lead@4.0.0: + resolution: {integrity: sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==} + engines: {node: '>=10.13.0'} + + levn@0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + liftoff@3.1.0: + resolution: {integrity: sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==} + engines: {node: '>= 0.8'} + + load-json-file@1.1.0: + resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} + engines: {node: '>=0.10.0'} + + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash._reinterpolate@3.0.0: + resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} + + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash.memoize@3.0.4: + resolution: {integrity: sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.template@4.5.0: + resolution: {integrity: sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==} + + lodash.templatesettings@4.2.0: + resolution: {integrity: sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + luxon@3.5.0: + resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==} + engines: {node: '>=12'} + + magic-string@0.23.2: + resolution: {integrity: sha512-oIUZaAxbcxYIp4AyLafV6OVKoB3YouZs0UTCJ8mOKBHNyJgGDaMJ4TgA+VylJh6fx7EQCC52XkbURxxG9IoJXA==} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + + make-iterator@1.0.1: + resolution: {integrity: sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==} + engines: {node: '>=0.10.0'} + + map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + + map-stream@0.0.7: + resolution: {integrity: sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==} + + map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + + matchdep@2.0.0: + resolution: {integrity: sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==} + engines: {node: '>= 0.10.0'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + maxmind@4.3.23: + resolution: {integrity: sha512-AMm4Eem0J0Y1EQJRVSdi2xevw5bJgUDd+lHyQwu0PvGUtK/4uOb8/uidmsrRZ/ST90UfF48H4ShAeFFWKvZ7bw==} + engines: {node: '>=12', npm: '>=6'} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + + merge-source-map@1.0.4: + resolution: {integrity: sha512-PGSmS0kfnTnMJCzJ16BLLCEe6oeYCamKFFdQKshi4BmM6FUwipjVOcBFGxqtQtirtAG4iZvHlqST9CpZKqlRjA==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + minify-stream@2.1.0: + resolution: {integrity: sha512-P5xE4EQRkn7Td54VGcgfDMFx1jmKPPIXCdcMfrbXS6cNHK4dO1LXwtYFb48hHrSmZfT+jlGImvHgSZEkbpNtCw==} + engines: {node: '>= 6'} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimist@0.0.8: + resolution: {integrity: sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mmdb-lib@2.1.1: + resolution: {integrity: sha512-yx8H/1H5AfnufiLnzzPqPf4yr/dKU9IFT1rPVwSkrKWHsQEeVVd6+X+L0nUbXhlEFTu3y/7hu38CFmEVgzvyeg==} + engines: {node: '>=10', npm: '>=6'} + + mocha@10.8.2: + resolution: {integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==} + engines: {node: '>= 14.0.0'} + hasBin: true + + module-deps@6.2.3: + resolution: {integrity: sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==} + engines: {node: '>= 0.8.0'} + hasBin: true + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + multi-stage-sourcemap@0.2.1: + resolution: {integrity: sha512-umaOM+8BZByZIB/ciD3dQLzTv50rEkkGJV78ta/tIVc/J/rfGZY5y1R+fBD3oTaolx41mK8rRcyGtYbDXlzx8Q==} + + multisplice@1.0.0: + resolution: {integrity: sha512-KU5tVjIdTGsMb92JlWwEZCGrvtI1ku9G9GuNbWdQT/Ici1ztFXX0L8lWpbbC3pISVMfBNL56wdqplHvva2XSlA==} + + mute-stdout@1.0.1: + resolution: {integrity: sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==} + engines: {node: '>= 0.10'} + + mutexify@1.4.0: + resolution: {integrity: sha512-pbYSsOrSB/AKN5h/WzzLRMFgZhClWccf2XIB4RSMC8JbquiB0e0/SH5AIfdQMdyHmYtv4seU7yV/TvAwPLJ1Yg==} + + nan@2.22.0: + resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} + + nanobench@2.1.1: + resolution: {integrity: sha512-z+Vv7zElcjN+OpzAxAquUayFLGK3JI/ubCl0Oh64YQqsTGG09CGqieJVQw4ui8huDnnAgrvTv93qi5UaOoNj8A==} + hasBin: true + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + + node-environment-flags@1.0.6: + resolution: {integrity: sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + nodemon@2.0.22: + resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} + engines: {node: '>=8.10.0'} + hasBin: true + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + now-and-later@2.0.1: + resolution: {integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==} + engines: {node: '>= 0.10'} + + now-and-later@3.0.0: + resolution: {integrity: sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==} + engines: {node: '>= 10.13.0'} + + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + + object-inspect@0.4.0: + resolution: {integrity: sha512-8WvkvUZiKAjjsy/63rJjA7jw9uyF0CLVLjBKEfnPHE3Jxvs1LgwqL2OmJN+LliIX1vrzKW+AAu02Cc+xv27ncQ==} + + object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} + + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@0.4.0: + resolution: {integrity: sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.defaults@1.1.0: + resolution: {integrity: sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==} + engines: {node: '>=0.10.0'} + + object.getownpropertydescriptors@2.1.8: + resolution: {integrity: sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A==} + engines: {node: '>= 0.8'} + + object.map@1.0.1: + resolution: {integrity: sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==} + engines: {node: '>=0.10.0'} + + object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + + object.reduce@1.0.1: + resolution: {integrity: sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==} + engines: {node: '>=0.10.0'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + ordered-read-streams@1.0.1: + resolution: {integrity: sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==} + + os-browserify@0.3.0: + resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + + os-locale@1.4.0: + resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} + engines: {node: '>=0.10.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parents@1.0.1: + resolution: {integrity: sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==} + + parse-asn1@5.1.7: + resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} + engines: {node: '>= 0.10'} + + parse-filepath@1.0.2: + resolution: {integrity: sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==} + engines: {node: '>=0.8'} + + parse-json@2.2.0: + resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} + engines: {node: '>=0.10.0'} + + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + + parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-dirname@1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + + path-exists@2.1.0: + resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} + engines: {node: '>=0.10.0'} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-platform@0.11.15: + resolution: {integrity: sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==} + engines: {node: '>= 0.8.0'} + + path-root-regex@0.1.2: + resolution: {integrity: sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==} + engines: {node: '>=0.10.0'} + + path-root@0.1.1: + resolution: {integrity: sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==} + engines: {node: '>=0.10.0'} + + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + + path-type@1.1.0: + resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} + engines: {node: '>=0.10.0'} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + + peggy@2.0.1: + resolution: {integrity: sha512-mBqfmdUAOVn7RILpXTbcRBhLfTR4Go0SresSnivGDdRylBOyVFJncFiVyCNNpPWq8HmgeRleXHs/Go4o8kQVXA==} + engines: {node: '>=10'} + hasBin: true + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pinkie-promise@2.0.1: + resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} + engines: {node: '>=0.10.0'} + + pinkie@2.0.4: + resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-dir@3.0.0: + resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} + engines: {node: '>=6'} + + plugin-error@1.0.1: + resolution: {integrity: sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==} + engines: {node: '>= 0.10'} + + plugin-error@2.0.1: + resolution: {integrity: sha512-zMakqvIDyY40xHOvzXka0kUvf40nYIuwRE8dWhti2WtjQZ31xAgBZBhxsK7vK3QbRXS1Xms/LO7B5cuAsfB2Gg==} + engines: {node: '>=10.13.0'} + + posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + prelude-ls@1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-plugin-sort-imports@1.8.6: + resolution: {integrity: sha512-jOEzFCyvdDL8geCmr4DP/VBKULZ6OaDQHBEmHTuFHf4EzWyedmwnHg2KawNy5rnrQ6gnCqwrfgymMQZctzCE1Q==} + peerDependencies: + typescript: '>4.0.0' + + prettier@2.6.2: + resolution: {integrity: sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==} + engines: {node: '>=10.13.0'} + hasBin: true + + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + + pretty-hrtime@1.0.3: + resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} + engines: {node: '>= 0.8'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + + public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + + pump@2.0.1: + resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + + pumpify@1.5.1: + resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + qs@6.13.1: + resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} + engines: {node: '>=0.6'} + + querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + + quote-stream@0.0.0: + resolution: {integrity: sha512-m4VtvjAMx00wgAS6eOy50ZDat1EBQeFKBIrtF/oxUt0MenEI33y7runJcRiOihc+JBBIt2aFFJhILIh4e9shJA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + read-only-stream@2.0.0: + resolution: {integrity: sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==} + + read-pkg-up@1.0.1: + resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} + engines: {node: '>=0.10.0'} + + read-pkg@1.1.0: + resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==} + engines: {node: '>=0.10.0'} + + readable-stream@1.0.34: + resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} + + readable-stream@1.1.14: + resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regenerate-unicode-properties@10.2.0: + resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + + regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + regexpu-core@6.2.0: + resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} + engines: {node: '>=4'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.12.0: + resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} + hasBin: true + + remove-bom-buffer@3.0.0: + resolution: {integrity: sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==} + engines: {node: '>=0.10.0'} + + remove-bom-stream@1.2.0: + resolution: {integrity: sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==} + engines: {node: '>= 0.10'} + + remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + + repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + replace-ext@1.0.1: + resolution: {integrity: sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==} + engines: {node: '>= 0.10'} + + replace-ext@2.0.0: + resolution: {integrity: sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==} + engines: {node: '>= 10'} + + replace-homedir@1.0.0: + resolution: {integrity: sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==} + engines: {node: '>= 0.10'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@1.0.1: + resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resolve-dir@1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-options@1.1.0: + resolution: {integrity: sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==} + engines: {node: '>= 0.10'} + + resolve-options@2.0.0: + resolution: {integrity: sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==} + engines: {node: '>= 10.13.0'} + + resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + ret@0.1.15: + resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} + engines: {node: '>=0.12'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scope-analyzer@2.1.2: + resolution: {integrity: sha512-5cfCmsTYV/wPaRIItNxatw02ua/MThdIUNnUOCYp+3LSEJvnG804ANw2VLaavNILIfWXF1D1G2KNANkBBvInwQ==} + + semver-greatest-satisfied-range@1.1.0: + resolution: {integrity: sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==} + engines: {node: '>= 0.10'} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.0.0: + resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + + shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + + shallow-copy@0.0.1: + resolution: {integrity: sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==} + + shasum-object@1.0.0: + resolution: {integrity: sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.2: + resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} + engines: {node: '>= 0.4'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-update-notifier@1.1.0: + resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} + engines: {node: '>=8.10.0'} + + slash@1.0.0: + resolution: {integrity: sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==} + engines: {node: '>=0.10.0'} + + snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + + snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + + snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + + source-map-generator@0.8.0: + resolution: {integrity: sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA==} + engines: {node: '>= 10'} + + source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + + source-map@0.1.43: + resolution: {integrity: sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==} + engines: {node: '>=0.8.0'} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + + sparkles@1.0.1: + resolution: {integrity: sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==} + engines: {node: '>= 0.10'} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + + static-eval@0.2.4: + resolution: {integrity: sha512-6dWWPfa/0+1zULdQi7ssT5EQZHsGK8LygBzhE/HdafNCo4e/Ibt7vLPfxBw9VcdVV+t0ARtN4ZAJKtApVc0A5Q==} + + static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + + static-js-yaml@1.0.0: + resolution: {integrity: sha512-SHd8UBXpEUeFEhexli7Nn1+fysyhU3LiQFKcwnqM3l5wzvJU6QoXg4cMtjjZjfc4ngRj934188v7FHgDyZ6U9A==} + + static-module@1.5.0: + resolution: {integrity: sha512-XTj7pQOHT33l77lK/Pu8UXqzI44C6LYAqwAc9hLTTESHRqJAFudBpReuopFPpoRr5CtOoSmGfFQC6FPlbDnyCw==} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + + stream-combiner2@1.1.1: + resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} + + stream-combiner@0.2.2: + resolution: {integrity: sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==} + + stream-composer@1.0.2: + resolution: {integrity: sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==} + + stream-exhaust@1.0.2: + resolution: {integrity: sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==} + + stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + + stream-splicer@2.0.1: + resolution: {integrity: sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==} + + streamx@2.21.1: + resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} + + string-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@2.0.0: + resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + subarg@1.0.0: + resolution: {integrity: sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==} + + supports-color@2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + sver-compat@1.5.0: + resolution: {integrity: sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==} + + syntax-error@1.4.0: + resolution: {integrity: sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==} + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + + ternary-stream@3.0.0: + resolution: {integrity: sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==} + + terser@3.17.0: + resolution: {integrity: sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + terser@4.8.1: + resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} + engines: {node: '>=6.0.0'} + hasBin: true + + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + through2-filter@3.0.0: + resolution: {integrity: sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==} + + through2@0.4.2: + resolution: {integrity: sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==} + + through2@0.6.5: + resolution: {integrity: sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==} + + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + + through2@3.0.2: + resolution: {integrity: sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==} + + through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + time-stamp@1.1.0: + resolution: {integrity: sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==} + engines: {node: '>=0.10.0'} + + timers-browserify@1.4.2: + resolution: {integrity: sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==} + engines: {node: '>=0.6.0'} + + tiny-lru@11.2.11: + resolution: {integrity: sha512-27BIW0dIWTYYoWNnqSmoNMKe5WIbkXsc0xaCQHd3/3xT2XMuMJrzHdrO9QBFR14emBz1Bu0dOAs2sCBBrvgPQA==} + engines: {node: '>=12'} + + tinyify@3.1.0: + resolution: {integrity: sha512-r4tHoDkWhhoItWbxJ3KCHXask3hJN7gCUkR5PLfnQzQagTA6oDkzhCbiEDHkMqo7Ck7vVSA1pTP1gDc9p1AC1w==} + + to-absolute-glob@2.0.2: + resolution: {integrity: sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==} + engines: {node: '>=0.10.0'} + + to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + + to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + + to-through@2.0.0: + resolution: {integrity: sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==} + engines: {node: '>= 0.10'} + + to-through@3.0.0: + resolution: {integrity: sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==} + engines: {node: '>=10.13.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + touch@3.1.1: + resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} + hasBin: true + + transform-ast@2.4.4: + resolution: {integrity: sha512-AxjeZAcIOUO2lev2GDe3/xZ1Q0cVGjIMk5IsriTy8zbWlsEnjeB025AhkhBJHoy997mXpLd4R+kRbvnnQVuQHQ==} + + tty-browserify@0.0.1: + resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} + + type-check@0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + type@2.7.3: + resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + + uglifyify@5.0.2: + resolution: {integrity: sha512-NcSk6pgoC+IgwZZ2tVLVHq+VNKSvLPlLkF5oUiHPVOJI0s/OlSVYEGXG9PCAH0hcyFZLyvt4KBdPAQBRlVDn1Q==} + + umd@3.0.3: + resolution: {integrity: sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==} + hasBin: true + + unassert@1.6.0: + resolution: {integrity: sha512-GoMtWTwGSxSFuRD0NKmbjlx3VJkgvSogzDzMPpJXYmBZv6MIWButsyMqEYhMx3NI4osXACcZA9mXiBteXyJtRw==} + + unassertify@2.1.1: + resolution: {integrity: sha512-YIAaIlc6/KC9Oib8cVZLlpDDhK1UTEuaDyx9BwD97xqxDZC0cJOqwFcs/Y6K3m73B5VzHsRTBLXNO0dxS/GkTw==} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + unc-path-regex@0.1.2: + resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} + engines: {node: '>=0.10.0'} + + undeclared-identifiers@1.1.3: + resolution: {integrity: sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==} + hasBin: true + + undefsafe@2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + + undertaker-registry@1.0.1: + resolution: {integrity: sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==} + engines: {node: '>= 0.10'} + + undertaker@1.3.0: + resolution: {integrity: sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==} + engines: {node: '>= 0.10'} + + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + undici@7.4.0: + resolution: {integrity: sha512-PUQM3/es3noM24oUn10u3kNNap0AbxESOmnssmW+dOi9yGwlUSi5nTNYl3bNbTkWOF8YZDkx2tCmj9OtQ3iGGw==} + engines: {node: '>=20.18.1'} + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.0: + resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + + unique-stream@2.3.1: + resolution: {integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + + upath@1.2.0: + resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} + engines: {node: '>=4'} + + update-browserslist-db@1.1.2: + resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} + + use@3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + + v8flags@3.2.0: + resolution: {integrity: sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==} + engines: {node: '>= 0.10'} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + value-or-function@3.0.0: + resolution: {integrity: sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==} + engines: {node: '>= 0.10'} + + value-or-function@4.0.0: + resolution: {integrity: sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==} + engines: {node: '>= 10.13.0'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + + vinyl-contents@2.0.0: + resolution: {integrity: sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==} + engines: {node: '>=10.13.0'} + + vinyl-fs@3.0.3: + resolution: {integrity: sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==} + engines: {node: '>= 0.10'} + + vinyl-fs@4.0.0: + resolution: {integrity: sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==} + engines: {node: '>=10.13.0'} + + vinyl-sourcemap@1.1.0: + resolution: {integrity: sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==} + engines: {node: '>= 0.10'} + + vinyl-sourcemap@2.0.0: + resolution: {integrity: sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==} + engines: {node: '>=10.13.0'} + + vinyl-sourcemaps-apply@0.2.1: + resolution: {integrity: sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==} + + vinyl@2.2.1: + resolution: {integrity: sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==} + engines: {node: '>= 0.10'} + + vinyl@3.0.0: + resolution: {integrity: sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==} + engines: {node: '>=10.13.0'} + + vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-module@1.0.0: + resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} + + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} + + wrap-ansi@2.1.0: + resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-comment@1.0.1: + resolution: {integrity: sha512-APccrMwl/ont0RHFTXNAQfM647duYYEfs6cngrIyTByTI0xbWnDnPSptFZhS68L4WCjt2ZxuhCFwuY6Pe88KZQ==} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xtend@2.1.2: + resolution: {integrity: sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==} + engines: {node: '>=0.4'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@3.2.2: + resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@5.0.1: + resolution: {integrity: sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@7.1.2: + resolution: {integrity: sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.26.5': {} + + '@babel/core@7.26.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.5 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.5 + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + convert-source-map: 2.0.0 + debug: 4.4.0(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.26.5': + dependencies: + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.25.9': + dependencies: + '@babel/types': 7.26.5 + + '@babel/helper-compilation-targets@7.26.5': + dependencies: + '@babel/compat-data': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.4 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@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.26.5(@babel/core@7.26.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.26.5 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + regexpu-core: 6.2.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + debug: 4.4.0(supports-color@8.1.1) + lodash.debounce: 4.0.8 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + '@babel/helper-member-expression-to-functions@7.25.9': + dependencies: + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.25.9': + dependencies: + '@babel/types': 7.26.5 + + '@babel/helper-plugin-utils@7.26.5': {} + + '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-wrap-function': 7.25.9 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + dependencies: + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helper-wrap-function@7.25.9': + dependencies: + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.26.0': + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.5 + + '@babel/node@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/register': 7.25.9(@babel/core@7.26.0) + commander: 6.2.1 + core-js: 3.40.0 + node-environment-flags: 1.0.6 + regenerator-runtime: 0.14.1 + v8flags: 3.2.0 + + '@babel/parser@7.26.5': + dependencies: + '@babel/types': 7.26.5 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + + '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-async-generator-functions@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.26.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.0) + '@babel/traverse': 7.26.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/template': 7.25.9 + + '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-exponentiation-operator@7.26.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-nullish-coalescing-operator@7.26.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + + '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + regenerator-transform: 0.15.2 + + '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-template-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-typeof-symbol@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/preset-env@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/compat-data': 7.26.5 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0) + '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoped-functions': 7.26.5(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-exponentiation-operator': 7.26.3(@babel/core@7.26.0) + '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.0) + '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.26.5(@babel/core@7.26.0) + '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-template-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typeof-symbol': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.0) + babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.26.0) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) + babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.26.0) + core-js-compat: 3.40.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/types': 7.26.5 + esutils: 2.0.3 + + '@babel/register@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + clone-deep: 4.0.1 + find-cache-dir: 2.1.0 + make-dir: 2.1.0 + pirates: 4.0.6 + source-map-support: 0.5.21 + + '@babel/runtime@7.26.0': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/template@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 + + '@babel/traverse@7.26.5': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.5 + '@babel/parser': 7.26.5 + '@babel/template': 7.25.9 + '@babel/types': 7.26.5 + debug: 4.4.0(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.26.5': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@esbuild/aix-ppc64@0.19.12': + optional: true + + '@esbuild/android-arm64@0.19.12': + optional: true + + '@esbuild/android-arm@0.19.12': + optional: true + + '@esbuild/android-x64@0.19.12': + optional: true + + '@esbuild/darwin-arm64@0.19.12': + optional: true + + '@esbuild/darwin-x64@0.19.12': + optional: true + + '@esbuild/freebsd-arm64@0.19.12': + optional: true + + '@esbuild/freebsd-x64@0.19.12': + optional: true + + '@esbuild/linux-arm64@0.19.12': + optional: true + + '@esbuild/linux-arm@0.19.12': + optional: true + + '@esbuild/linux-ia32@0.19.12': + optional: true + + '@esbuild/linux-loong64@0.19.12': + optional: true + + '@esbuild/linux-mips64el@0.19.12': + optional: true + + '@esbuild/linux-ppc64@0.19.12': + optional: true + + '@esbuild/linux-riscv64@0.19.12': + optional: true + + '@esbuild/linux-s390x@0.19.12': + optional: true + + '@esbuild/linux-x64@0.19.12': + optional: true + + '@esbuild/netbsd-x64@0.19.12': + optional: true + + '@esbuild/openbsd-x64@0.19.12': + optional: true + + '@esbuild/sunos-x64@0.19.12': + optional: true + + '@esbuild/win32-arm64@0.19.12': + optional: true + + '@esbuild/win32-ia32@0.19.12': + optional: true + + '@esbuild/win32-x64@0.19.12': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.4.0(supports-color@8.1.1) + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.1': {} + + '@goto-bus-stop/common-shake@2.4.1': + dependencies: + acorn-walk: 7.2.0 + debug: 3.2.7(supports-color@5.5.0) + escope: 3.6.0 + transitivePeerDependencies: + - supports-color + + '@goto-bus-stop/envify@5.0.0': + dependencies: + acorn-node: 2.0.1 + dash-ast: 2.0.1 + multisplice: 1.0.0 + through2: 2.0.5 + + '@gulpjs/to-absolute-glob@4.0.0': + dependencies: + is-negated-glob: 1.0.0 + + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@leichtgewicht/ip-codec@2.0.5': {} + + '@maxmind/geoip2-node@5.0.0': + dependencies: + ip6addr: 0.2.5 + maxmind: 4.3.23 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.18.0 + + '@types/eslint@8.56.12': + dependencies: + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.6': {} + + '@types/expect@1.20.4': {} + + '@types/glob-stream@8.0.2': + dependencies: + '@types/node': 22.10.5 + '@types/picomatch': 3.0.1 + '@types/streamx': 2.9.5 + + '@types/gulp@4.0.17': + dependencies: + '@types/node': 22.10.5 + '@types/undertaker': 1.2.11 + '@types/vinyl-fs': 3.0.5 + chokidar: 3.6.0 + + '@types/http-proxy@1.17.15': + dependencies: + '@types/node': 22.10.5 + + '@types/json-schema@7.0.15': {} + + '@types/luxon@3.4.2': {} + + '@types/node@22.10.5': + dependencies: + undici-types: 6.20.0 + + '@types/picomatch@3.0.1': {} + + '@types/streamx@2.9.5': + dependencies: + '@types/node': 22.10.5 + + '@types/undertaker-registry@1.0.4': {} + + '@types/undertaker@1.2.11': + dependencies: + '@types/node': 22.10.5 + '@types/undertaker-registry': 1.0.4 + async-done: 1.3.2 + + '@types/vinyl-fs@3.0.5': + dependencies: + '@types/glob-stream': 8.0.2 + '@types/node': 22.10.5 + '@types/vinyl': 2.0.12 + + '@types/vinyl@2.0.12': + dependencies: + '@types/expect': 1.20.4 + '@types/node': 22.10.5 + + '@ungap/structured-clone@1.2.1': {} + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn-node@1.8.2: + dependencies: + acorn: 7.4.1 + acorn-walk: 7.2.0 + xtend: 4.0.2 + + acorn-node@2.0.1: + dependencies: + acorn: 7.4.1 + acorn-walk: 7.2.0 + xtend: 4.0.2 + + acorn-walk@7.2.0: {} + + acorn@5.7.4: {} + + acorn@7.4.1: {} + + acorn@8.14.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + amdefine@1.0.1: {} + + ansi-colors@1.1.0: + dependencies: + ansi-wrap: 0.1.0 + + ansi-colors@4.1.3: {} + + ansi-gray@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-regex@2.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-styles@2.2.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-wrap@0.1.0: {} + + anymatch@2.0.0: + dependencies: + micromatch: 3.1.10 + normalize-path: 2.1.1 + transitivePeerDependencies: + - supports-color + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + append-buffer@1.0.2: + dependencies: + buffer-equal: 1.0.1 + + archy@1.0.0: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + arr-diff@4.0.0: {} + + arr-filter@1.1.2: + dependencies: + make-iterator: 1.0.1 + + arr-flatten@1.1.0: {} + + arr-map@2.0.2: + dependencies: + make-iterator: 1.0.1 + + arr-union@3.1.0: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + is-array-buffer: 3.0.5 + + array-each@1.0.1: {} + + array-flatten@1.1.1: {} + + array-from@2.1.1: {} + + array-initial@1.1.0: + dependencies: + array-slice: 1.1.0 + is-number: 4.0.0 + + array-last@1.3.0: + dependencies: + is-number: 4.0.0 + + array-slice@1.1.0: {} + + array-sort@1.0.0: + dependencies: + default-compare: 1.0.0 + get-value: 2.0.6 + kind-of: 5.1.0 + + array-unique@0.3.2: {} + + array.prototype.reduce@1.0.7: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-array-method-boxes-properly: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + is-string: 1.1.1 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + is-array-buffer: 3.0.5 + + asn1.js@4.10.1: + dependencies: + bn.js: 4.12.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + assert-plus@1.0.0: {} + + assert@1.5.1: + dependencies: + object.assign: 4.1.7 + util: 0.10.4 + + assertion-error@1.1.0: {} + + assign-symbols@1.0.0: {} + + async-done@1.3.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + process-nextick-args: 2.0.1 + stream-exhaust: 1.0.2 + + async-each@1.0.6: {} + + async-settle@1.0.0: + dependencies: + async-done: 1.3.2 + + atob@2.1.2: {} + + automerge@1.0.1-preview.7: + dependencies: + fast-sha256: 1.3.0 + pako: 2.1.0 + uuid: 3.4.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + axios@0.21.4: + dependencies: + follow-redirects: 1.15.9(debug@4.4.0) + transitivePeerDependencies: + - debug + + b4a@1.6.7: {} + + babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): + dependencies: + '@babel/compat-data': 7.26.5 + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + core-js-compat: 3.40.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + babel-plugin-relative-path-import@2.0.1: + dependencies: + slash: 1.0.0 + + babelify@10.0.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + + bach@1.2.0: + dependencies: + arr-filter: 1.1.2 + arr-flatten: 1.1.0 + arr-map: 2.0.2 + array-each: 1.0.1 + array-initial: 1.1.0 + array-last: 1.3.0 + async-done: 1.3.2 + async-settle: 1.0.0 + now-and-later: 2.0.1 + + balanced-match@1.0.2: {} + + bare-events@2.5.4: + optional: true + + base64-js@1.5.1: {} + + base@0.11.2: + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.1 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + + binary-extensions@1.13.1: {} + + binary-extensions@2.3.0: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + optional: true + + bl@5.1.0: + dependencies: + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 3.6.2 + + bn.js@4.12.1: {} + + bn.js@5.2.1: {} + + body-parser@1.20.3: + 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 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@2.3.2: + dependencies: + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2 + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brorand@1.1.0: {} + + browser-pack-flat@3.5.0: + dependencies: + JSONStream: 1.3.5 + combine-source-map: 0.8.0 + convert-source-map: 1.9.0 + count-lines: 0.1.2 + dedent: 0.7.0 + estree-is-member-expression: 1.0.0 + estree-is-require: 1.0.0 + esutils: 2.0.3 + path-parse: 1.0.7 + scope-analyzer: 2.1.2 + stream-combiner: 0.2.2 + through2: 3.0.2 + transform-ast: 2.4.4 + umd: 3.0.3 + wrap-comment: 1.0.1 + + browser-pack@6.1.0: + dependencies: + JSONStream: 1.3.5 + combine-source-map: 0.8.0 + defined: 1.0.1 + safe-buffer: 5.2.1 + through2: 2.0.5 + umd: 3.0.3 + + browser-process-hrtime@0.1.3: {} + + browser-resolve@2.0.0: + dependencies: + resolve: 1.22.10 + + browser-stdout@1.3.1: {} + + browser-unpack@1.4.3: + dependencies: + acorn-node: 1.8.2 + concat-stream: 1.6.2 + minimist: 1.2.8 + + browserify-aes@1.2.0: + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.6 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + browserify-cipher@1.0.1: + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + + browserify-des@1.0.2: + dependencies: + cipher-base: 1.0.6 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + browserify-rsa@4.1.1: + dependencies: + bn.js: 5.2.1 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + browserify-sign@4.2.3: + dependencies: + bn.js: 5.2.1 + browserify-rsa: 4.1.1 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.6.1 + hash-base: 3.0.5 + inherits: 2.0.4 + parse-asn1: 5.1.7 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + + browserify-zlib@0.2.0: + dependencies: + pako: 1.0.11 + + browserify@17.0.1: + dependencies: + JSONStream: 1.3.5 + assert: 1.5.1 + browser-pack: 6.1.0 + browser-resolve: 2.0.0 + browserify-zlib: 0.2.0 + buffer: 5.2.1 + cached-path-relative: 1.1.0 + concat-stream: 1.6.2 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + crypto-browserify: 3.12.1 + defined: 1.0.1 + deps-sort: 2.0.1 + domain-browser: 1.2.0 + duplexer2: 0.1.4 + events: 3.3.0 + glob: 7.2.3 + hasown: 2.0.2 + htmlescape: 1.1.1 + https-browserify: 1.0.0 + inherits: 2.0.4 + insert-module-globals: 7.2.1 + labeled-stream-splicer: 2.0.2 + mkdirp-classic: 0.5.3 + module-deps: 6.2.3 + os-browserify: 0.3.0 + parents: 1.0.1 + path-browserify: 1.0.1 + process: 0.11.10 + punycode: 1.4.1 + querystring-es3: 0.2.1 + read-only-stream: 2.0.0 + readable-stream: 2.3.8 + resolve: 1.22.10 + shasum-object: 1.0.0 + shell-quote: 1.8.2 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + subarg: 1.0.0 + syntax-error: 1.4.0 + through2: 2.0.5 + timers-browserify: 1.4.2 + tty-browserify: 0.0.1 + url: 0.11.4 + util: 0.12.5 + vm-browserify: 1.1.2 + xtend: 4.0.2 + + browserslist@4.24.4: + dependencies: + caniuse-lite: 1.0.30001692 + electron-to-chromium: 1.5.80 + node-releases: 2.0.19 + update-browserslist-db: 1.1.2(browserslist@4.24.4) + + buffer-equal@1.0.1: {} + + buffer-from@1.1.2: {} + + buffer-xor@1.0.3: {} + + buffer@5.2.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + builtin-status-codes@3.0.0: {} + + bundle-collapser@1.4.0: + dependencies: + browser-pack: 6.1.0 + browser-unpack: 1.4.3 + concat-stream: 1.6.2 + falafel: 2.2.5 + minimist: 1.2.8 + through2: 2.0.5 + + bytes@3.1.2: {} + + cache-base@1.0.1: + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.1 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 + + cached-path-relative@1.1.0: {} + + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.7 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.7 + + call-matcher@2.0.0: + dependencies: + deep-equal: 1.1.2 + espurify: 2.1.1 + estraverse: 4.3.0 + + callsites@3.1.0: {} + + camelcase@3.0.0: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001692: {} + + chai@4.5.0: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.4 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.1.0 + + chalk@1.1.3: + dependencies: + ansi-styles: 2.2.1 + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + check-error@1.0.3: + dependencies: + get-func-name: 2.0.2 + + chokidar@2.1.8: + dependencies: + anymatch: 2.0.0 + async-each: 1.0.6 + braces: 2.3.2 + glob-parent: 3.1.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 4.0.3 + normalize-path: 3.0.0 + path-is-absolute: 1.0.1 + readdirp: 2.2.1 + upath: 1.2.0 + optionalDependencies: + fsevents: 1.2.13 + transitivePeerDependencies: + - supports-color + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + cipher-base@1.0.6: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + class-utils@0.3.6: + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + + cliui@3.2.0: + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + wrap-ansi: 2.1.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-buffer@1.0.0: {} + + clone-deep@4.0.1: + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + + clone-stats@1.0.0: {} + + clone@2.1.2: {} + + cloneable-readable@1.1.3: + dependencies: + inherits: 2.0.4 + process-nextick-args: 2.0.1 + readable-stream: 2.3.8 + + code-point-at@1.1.0: {} + + collection-map@1.0.0: + dependencies: + arr-map: 2.0.2 + for-own: 1.0.0 + make-iterator: 1.0.1 + + collection-visit@1.0.0: + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-support@1.1.3: {} + + combine-source-map@0.8.0: + dependencies: + convert-source-map: 1.1.3 + inline-source-map: 0.6.3 + lodash.memoize: 3.0.4 + source-map: 0.5.7 + + commander@2.20.3: {} + + commander@6.2.1: {} + + commander@9.5.0: {} + + common-shakeify@1.1.2: + dependencies: + '@goto-bus-stop/common-shake': 2.4.1 + convert-source-map: 1.9.0 + through2: 2.0.5 + transform-ast: 2.4.4 + wrap-comment: 1.0.1 + transitivePeerDependencies: + - supports-color + + commondir@1.0.1: {} + + component-emitter@1.3.1: {} + + concat-map@0.0.1: {} + + concat-stream@1.6.2: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + + concat-stream@2.0.0: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + typedarray: 0.0.6 + + concat-with-sourcemaps@1.1.0: + dependencies: + source-map: 0.6.1 + + connect-history-api-fallback@2.0.0: {} + + console-browserify@1.2.0: {} + + constants-browserify@1.0.0: {} + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + convert-source-map@1.1.3: {} + + convert-source-map@1.9.0: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.0.6: {} + + cookie@0.7.1: {} + + copy-descriptor@0.1.1: {} + + copy-props@2.0.5: + dependencies: + each-props: 1.3.2 + is-plain-object: 5.0.0 + + core-js-compat@3.40.0: + dependencies: + browserslist: 4.24.4 + + core-js@3.40.0: {} + + core-util-is@1.0.2: {} + + core-util-is@1.0.3: {} + + count-lines@0.1.2: {} + + create-ecdh@4.0.4: + dependencies: + bn.js: 4.12.1 + elliptic: 6.6.1 + + create-hash@1.2.0: + dependencies: + cipher-base: 1.0.6 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + + create-hmac@1.1.7: + dependencies: + cipher-base: 1.0.6 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + cron@3.5.0: + dependencies: + '@types/luxon': 3.4.2 + luxon: 3.5.0 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypto-browserify@3.12.1: + dependencies: + browserify-cipher: 1.0.1 + browserify-sign: 4.2.3 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + hash-base: 3.0.5 + inherits: 2.0.4 + pbkdf2: 3.1.2 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 + + d@1.0.2: + dependencies: + es5-ext: 0.10.64 + type: 2.7.3 + + dash-ast@1.0.0: {} + + dash-ast@2.0.1: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@3.2.7(supports-color@5.5.0): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 5.5.0 + + debug@4.4.0(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + decamelize@1.2.0: {} + + decamelize@4.0.0: {} + + decode-uri-component@0.2.2: {} + + dedent@0.7.0: {} + + deep-eql@4.1.4: + dependencies: + type-detect: 4.1.0 + + deep-equal@1.1.2: + dependencies: + is-arguments: 1.2.0 + is-date-object: 1.1.0 + is-regex: 1.2.1 + object-is: 1.1.6 + object-keys: 1.1.1 + regexp.prototype.flags: 1.5.4 + + deep-is@0.1.4: {} + + default-compare@1.0.0: + dependencies: + kind-of: 5.1.0 + + default-resolution@2.0.0: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + define-property@0.2.5: + dependencies: + is-descriptor: 0.1.7 + + define-property@1.0.0: + dependencies: + is-descriptor: 1.0.3 + + define-property@2.0.2: + dependencies: + is-descriptor: 1.0.3 + isobject: 3.0.1 + + defined@1.0.1: {} + + depd@2.0.0: {} + + deps-sort@2.0.1: + dependencies: + JSONStream: 1.3.5 + shasum-object: 1.0.0 + subarg: 1.0.0 + through2: 2.0.5 + + des.js@1.1.0: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + destroy@1.2.0: {} + + detect-file@1.0.0: {} + + detective@5.2.1: + dependencies: + acorn-node: 1.8.2 + defined: 1.0.1 + minimist: 1.2.8 + + diff@5.2.0: {} + + diffie-hellman@5.0.3: + dependencies: + bn.js: 4.12.1 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + + dns-packet@5.6.1: + dependencies: + '@leichtgewicht/ip-codec': 2.0.5 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + domain-browser@1.2.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer2@0.0.2: + dependencies: + readable-stream: 1.1.14 + + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + + duplexer@0.1.2: {} + + duplexify@3.7.1: + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 2.3.8 + stream-shift: 1.0.3 + + duplexify@4.1.3: + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 + + each-props@1.3.2: + dependencies: + is-plain-object: 2.0.4 + object.defaults: 1.1.0 + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.80: {} + + elliptic@6.6.1: + dependencies: + bn.js: 4.12.1 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + emoji-regex@8.0.0: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.23.9: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.0 + math-intrinsics: 1.1.0 + object-inspect: 1.13.3 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.18 + + es-array-method-boxes-properly@1.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + es5-ext@0.10.64: + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 + next-tick: 1.1.0 + + es6-iterator@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 + + es6-map@0.1.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-set: 0.1.6 + es6-symbol: 3.1.4 + event-emitter: 0.3.5 + + es6-set@0.1.6: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + event-emitter: 0.3.5 + type: 2.7.3 + + es6-symbol@3.1.4: + dependencies: + d: 1.0.2 + ext: 1.7.0 + + es6-weak-map@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + + esbuild@0.19.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + escodegen@0.0.28: + dependencies: + esprima: 1.0.4 + estraverse: 1.3.2 + optionalDependencies: + source-map: 0.7.4 + + escodegen@1.14.3: + dependencies: + esprima: 4.0.1 + estraverse: 4.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + + escodegen@1.3.3: + dependencies: + esprima: 1.1.1 + estraverse: 1.5.1 + esutils: 1.0.0 + optionalDependencies: + source-map: 0.1.43 + + escope@3.6.0: + dependencies: + es6-map: 0.1.5 + es6-weak-map: 2.0.3 + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.1 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + esniff@2.0.1: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.3 + + espree@9.6.1: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 3.4.3 + + esprima@1.0.4: {} + + esprima@1.1.1: {} + + esprima@4.0.1: {} + + espurify@2.1.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@1.3.2: {} + + estraverse@1.5.1: {} + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + estree-is-function@1.0.0: {} + + estree-is-identifier@1.0.0: {} + + estree-is-member-expression@1.0.0: {} + + estree-is-require@1.0.0: + dependencies: + estree-is-identifier: 1.0.0 + + esutils@1.0.0: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + event-emitter@0.3.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + + eventemitter3@4.0.7: {} + + events@3.3.0: {} + + evp_bytestokey@1.0.3: + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + + expand-brackets@2.1.4: + dependencies: + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + expand-tilde@2.0.2: + dependencies: + homedir-polyfill: 1.0.3 + + express@4.21.2: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + ext@1.7.0: + dependencies: + type: 2.7.3 + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend-shallow@3.0.2: + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + + extend@3.0.2: {} + + extglob@2.0.4: + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4 + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + extsprintf@1.3.0: {} + + falafel@2.2.5: + dependencies: + acorn: 7.4.1 + isarray: 2.0.5 + + fancy-log@1.3.3: + dependencies: + ansi-gray: 0.1.1 + color-support: 1.1.3 + parse-node-version: 1.0.1 + time-stamp: 1.1.0 + + fancy-log@2.0.0: + dependencies: + color-support: 1.1.3 + + fast-deep-equal@3.1.3: {} + + fast-fifo@1.3.2: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@1.1.4: {} + + fast-levenshtein@2.0.6: {} + + fast-safe-stringify@2.1.1: {} + + fast-sha256@1.3.0: {} + + fastq@1.18.0: + dependencies: + reusify: 1.0.4 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + file-uri-to-path@1.0.0: + optional: true + + fill-range@4.0.0: + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + find-cache-dir@2.1.0: + dependencies: + commondir: 1.0.1 + make-dir: 2.1.0 + pkg-dir: 3.0.0 + + find-up@1.1.2: + dependencies: + path-exists: 2.1.0 + pinkie-promise: 2.0.1 + + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + findup-sync@2.0.0: + dependencies: + detect-file: 1.0.0 + is-glob: 3.1.0 + micromatch: 3.1.10 + resolve-dir: 1.0.1 + transitivePeerDependencies: + - supports-color + + findup-sync@3.0.0: + dependencies: + detect-file: 1.0.0 + is-glob: 4.0.3 + micromatch: 3.1.10 + resolve-dir: 1.0.1 + transitivePeerDependencies: + - supports-color + + fined@1.2.0: + dependencies: + expand-tilde: 2.0.2 + is-plain-object: 2.0.4 + object.defaults: 1.1.0 + object.pick: 1.3.0 + parse-filepath: 1.0.2 + + flagged-respawn@1.0.1: {} + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.2 + keyv: 4.5.4 + rimraf: 3.0.2 + + flat@5.0.2: {} + + flatted@3.3.2: {} + + flush-write-stream@1.1.1: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + follow-redirects@1.15.9(debug@4.4.0): + optionalDependencies: + debug: 4.4.0(supports-color@8.1.1) + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + for-in@1.0.2: {} + + for-own@1.0.0: + dependencies: + for-in: 1.0.2 + + fork-stream@0.0.4: {} + + forwarded@0.2.0: {} + + fragment-cache@0.2.1: + dependencies: + map-cache: 0.2.2 + + fresh@0.5.2: {} + + from2-string@1.1.0: + dependencies: + from2: 2.3.0 + + from2@2.3.0: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + fs-mkdirp-stream@1.0.0: + dependencies: + graceful-fs: 4.2.11 + through2: 2.0.5 + + fs-mkdirp-stream@2.0.1: + dependencies: + graceful-fs: 4.2.11 + streamx: 2.21.1 + + fs.realpath@1.0.0: {} + + fsevents@1.2.13: + dependencies: + bindings: 1.5.0 + nan: 2.22.0 + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + get-assigned-identifiers@1.2.0: {} + + get-caller-file@1.0.3: {} + + get-caller-file@2.0.5: {} + + get-func-name@2.0.2: {} + + get-intrinsic@1.2.7: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.0.0 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + + get-value@2.0.6: {} + + glob-parent@3.1.0: + dependencies: + is-glob: 3.1.0 + path-dirname: 1.0.2 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-stream@6.1.0: + dependencies: + extend: 3.0.2 + glob: 7.2.3 + glob-parent: 3.1.0 + is-negated-glob: 1.0.0 + ordered-read-streams: 1.0.1 + pumpify: 1.5.1 + readable-stream: 2.3.8 + remove-trailing-separator: 1.1.0 + to-absolute-glob: 2.0.2 + unique-stream: 2.3.1 + + glob-stream@8.0.2: + dependencies: + '@gulpjs/to-absolute-glob': 4.0.0 + anymatch: 3.1.3 + fastq: 1.18.0 + glob-parent: 6.0.2 + is-glob: 4.0.3 + is-negated-glob: 1.0.0 + normalize-path: 3.0.0 + streamx: 2.21.1 + + glob-watcher@5.0.5: + dependencies: + anymatch: 2.0.0 + async-done: 1.3.2 + chokidar: 2.1.8 + is-negated-glob: 1.0.0 + just-debounce: 1.1.0 + normalize-path: 3.0.0 + object.defaults: 1.1.0 + transitivePeerDependencies: + - supports-color + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + global-modules@1.0.0: + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + + global-prefix@1.0.2: + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + + globals@11.12.0: {} + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + glogg@1.0.2: + dependencies: + sparkles: 1.0.1 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + gulp-babel@8.0.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + plugin-error: 1.0.1 + replace-ext: 1.0.1 + through2: 2.0.5 + vinyl-sourcemaps-apply: 0.2.1 + + gulp-cli@2.3.0: + dependencies: + ansi-colors: 1.1.0 + archy: 1.0.0 + array-sort: 1.0.0 + color-support: 1.1.3 + concat-stream: 1.6.2 + copy-props: 2.0.5 + fancy-log: 1.3.3 + gulplog: 1.0.0 + interpret: 1.4.0 + isobject: 3.0.1 + liftoff: 3.1.0 + matchdep: 2.0.0 + mute-stdout: 1.0.1 + pretty-hrtime: 1.0.3 + replace-homedir: 1.0.0 + semver-greatest-satisfied-range: 1.1.0 + v8flags: 3.2.0 + yargs: 7.1.2 + transitivePeerDependencies: + - supports-color + + gulp-eslint-new@1.9.1: + dependencies: + '@types/eslint': 8.56.12 + '@types/node': 22.10.5 + eslint: 8.57.1 + fancy-log: 2.0.0 + plugin-error: 2.0.1 + semver: 7.6.3 + ternary-stream: 3.0.0 + vinyl-fs: 4.0.0 + transitivePeerDependencies: + - supports-color + + gulp-file@0.4.0: + dependencies: + through2: 0.4.2 + vinyl: 2.2.1 + + gulp-header@2.0.9: + dependencies: + concat-with-sourcemaps: 1.1.0 + lodash.template: 4.5.0 + map-stream: 0.0.7 + through2: 2.0.5 + + gulp-prettier@4.0.0: + dependencies: + plugin-error: 1.0.1 + prettier: 2.6.2 + through2: 4.0.2 + + gulp-tap@2.0.0: + dependencies: + through2: 3.0.2 + + gulp@4.0.2: + dependencies: + glob-watcher: 5.0.5 + gulp-cli: 2.3.0 + undertaker: 1.3.0 + vinyl-fs: 3.0.3 + transitivePeerDependencies: + - supports-color + + gulplog@1.0.0: + dependencies: + glogg: 1.0.2 + + has-ansi@2.0.0: + dependencies: + ansi-regex: 2.1.1 + + has-bigints@1.1.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + has-value@0.3.1: + dependencies: + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 + + has-value@1.0.0: + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + + has-values@0.1.4: {} + + has-values@1.0.0: + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + + has@1.0.4: {} + + hash-base@3.0.5: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + homedir-polyfill@1.0.3: + dependencies: + parse-passwd: 1.0.0 + + hosted-git-info@2.8.9: {} + + htmlescape@1.1.1: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + http-proxy-middleware@3.0.3: + dependencies: + '@types/http-proxy': 1.17.15 + debug: 4.4.0(supports-color@8.1.1) + http-proxy: 1.18.1(patch_hash=8071c23044f455271f4d4074ae4c7b81beec17a03aefd158d5f4edd4ef751c11)(debug@4.4.0) + is-glob: 4.0.3 + is-plain-object: 5.0.0 + micromatch: 4.0.8 + transitivePeerDependencies: + - supports-color + + http-proxy@1.18.1(patch_hash=8071c23044f455271f4d4074ae4c7b81beec17a03aefd158d5f4edd4ef751c11)(debug@4.4.0): + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.9(debug@4.4.0) + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + + https-browserify@1.0.0: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore-by-default@1.0.1: {} + + ignore@5.3.2: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.3: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + inline-source-map@0.6.3: + dependencies: + source-map: 0.5.7 + + insert-module-globals@7.2.1: + dependencies: + JSONStream: 1.3.5 + acorn-node: 1.8.2 + combine-source-map: 0.8.0 + concat-stream: 1.6.2 + is-buffer: 1.1.6 + path-is-absolute: 1.0.1 + process: 0.11.10 + through2: 2.0.5 + undeclared-identifiers: 1.1.3 + xtend: 4.0.2 + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + interpret@1.4.0: {} + + invert-kv@1.0.0: {} + + ip-address@9.0.5: + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + + ip6addr@0.2.5: + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + + ipaddr.js@1.9.1: {} + + is-absolute@1.0.0: + dependencies: + is-relative: 1.0.0 + is-windows: 1.0.2 + + is-accessor-descriptor@1.0.1: + dependencies: + hasown: 2.0.2 + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.0: + dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@1.0.1: + dependencies: + binary-extensions: 1.13.1 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-buffer@1.1.6: {} + + is-buffer@2.0.5: {} + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-descriptor@1.0.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-descriptor@0.1.7: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + + is-descriptor@1.0.3: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + + is-extendable@0.1.1: {} + + is-extendable@1.0.1: + dependencies: + is-plain-object: 2.0.4 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.3 + + is-fullwidth-code-point@1.0.0: + dependencies: + number-is-nan: 1.0.1 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.1.0: + dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@3.1.0: + dependencies: + is-extglob: 2.1.1 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negated-glob@1.0.0: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-number@3.0.0: + dependencies: + kind-of: 3.2.2 + + is-number@4.0.0: {} + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-plain-obj@2.1.0: {} + + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + + is-plain-object@5.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-relative@1.0.0: + dependencies: + is-unc-path: 1.0.0 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.3 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.3 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.18 + + is-unc-path@1.0.0: + dependencies: + unc-path-regex: 0.1.2 + + is-unicode-supported@0.1.0: {} + + is-utf8@0.2.1: {} + + is-valid-glob@1.0.0: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.1.0: + dependencies: + call-bound: 1.0.3 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + + is-windows@1.0.2: {} + + isarray@0.0.1: {} + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isobject@2.1.0: + dependencies: + isarray: 1.0.0 + + isobject@3.0.1: {} + + js-base64@3.7.7: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsbn@1.1.0: {} + + jsesc@3.0.2: {} + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema@0.4.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonparse@1.3.1: {} + + jsprim@2.0.2: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + + jsrsasign@11.1.0: {} + + just-debounce@1.1.0: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kind-of@3.2.2: + dependencies: + is-buffer: 1.1.6 + + kind-of@4.0.0: + dependencies: + is-buffer: 1.1.6 + + kind-of@5.1.0: {} + + kind-of@6.0.3: {} + + labeled-stream-splicer@2.0.2: + dependencies: + inherits: 2.0.4 + stream-splicer: 2.0.1 + + last-run@1.1.1: + dependencies: + default-resolution: 2.0.0 + es6-weak-map: 2.0.3 + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + lcid@1.0.0: + dependencies: + invert-kv: 1.0.0 + + lead@1.0.0: + dependencies: + flush-write-stream: 1.1.1 + + lead@4.0.0: {} + + levn@0.3.0: + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + liftoff@3.1.0: + dependencies: + extend: 3.0.2 + findup-sync: 3.0.0 + fined: 1.2.0 + flagged-respawn: 1.0.1 + is-plain-object: 2.0.4 + object.map: 1.0.1 + rechoir: 0.6.2 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + load-json-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 2.2.0 + pify: 2.3.0 + pinkie-promise: 2.0.1 + strip-bom: 2.0.0 + + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash._reinterpolate@3.0.0: {} + + lodash.debounce@4.0.8: {} + + lodash.memoize@3.0.4: {} + + lodash.merge@4.6.2: {} + + lodash.template@4.5.0: + dependencies: + lodash._reinterpolate: 3.0.0 + lodash.templatesettings: 4.2.0 + + lodash.templatesettings@4.2.0: + dependencies: + lodash._reinterpolate: 3.0.0 + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + loupe@2.3.7: + dependencies: + get-func-name: 2.0.2 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + luxon@3.5.0: {} + + magic-string@0.23.2: + dependencies: + sourcemap-codec: 1.4.8 + + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + + make-iterator@1.0.1: + dependencies: + kind-of: 6.0.3 + + map-cache@0.2.2: {} + + map-stream@0.0.7: {} + + map-visit@1.0.0: + dependencies: + object-visit: 1.0.1 + + matchdep@2.0.0: + dependencies: + findup-sync: 2.0.0 + micromatch: 3.1.10 + resolve: 1.22.10 + stack-trace: 0.0.10 + transitivePeerDependencies: + - supports-color + + math-intrinsics@1.1.0: {} + + maxmind@4.3.23: + dependencies: + mmdb-lib: 2.1.1 + tiny-lru: 11.2.11 + + md5.js@1.3.5: + dependencies: + hash-base: 3.0.5 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + media-typer@0.3.0: {} + + merge-descriptors@1.0.3: {} + + merge-source-map@1.0.4: + dependencies: + source-map: 0.5.7 + + merge-stream@2.0.0: {} + + methods@1.1.2: {} + + micromatch@3.1.10: + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + extglob: 2.0.4 + fragment-cache: 0.2.1 + kind-of: 6.0.3 + nanomatch: 1.2.13 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + miller-rabin@4.0.1: + dependencies: + bn.js: 4.12.1 + brorand: 1.1.0 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + + minify-stream@2.1.0: + dependencies: + concat-stream: 2.0.0 + convert-source-map: 1.9.0 + duplexify: 4.1.3 + from2-string: 1.1.0 + terser: 4.8.1 + xtend: 4.0.2 + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimist@0.0.8: {} + + minimist@1.2.8: {} + + mixin-deep@1.3.2: + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + + mkdirp-classic@0.5.3: {} + + mmdb-lib@2.1.1: {} + + mocha@10.8.2: + dependencies: + ansi-colors: 4.1.3 + browser-stdout: 1.3.1 + chokidar: 3.6.0 + debug: 4.4.0(supports-color@8.1.1) + diff: 5.2.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.1.6 + ms: 2.1.3 + serialize-javascript: 6.0.2 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.5.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + yargs-unparser: 2.0.0 + + module-deps@6.2.3: + dependencies: + JSONStream: 1.3.5 + browser-resolve: 2.0.0 + cached-path-relative: 1.1.0 + concat-stream: 1.6.2 + defined: 1.0.1 + detective: 5.2.1 + duplexer2: 0.1.4 + inherits: 2.0.4 + parents: 1.0.1 + readable-stream: 2.3.8 + resolve: 1.22.10 + stream-combiner2: 1.1.1 + subarg: 1.0.0 + through2: 2.0.5 + xtend: 4.0.2 + + ms@2.0.0: {} + + ms@2.1.3: {} + + multi-stage-sourcemap@0.2.1: + dependencies: + source-map: 0.1.43 + + multisplice@1.0.0: {} + + mute-stdout@1.0.1: {} + + mutexify@1.4.0: + dependencies: + queue-tick: 1.0.1 + + nan@2.22.0: + optional: true + + nanobench@2.1.1: + dependencies: + browser-process-hrtime: 0.1.3 + chalk: 1.1.3 + mutexify: 1.4.0 + pretty-hrtime: 1.0.3 + + nanoid@3.3.8: {} + + nanomatch@1.2.13: + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + natural-compare@1.4.0: {} + + negotiator@0.6.3: {} + + next-tick@1.1.0: {} + + node-environment-flags@1.0.6: + dependencies: + object.getownpropertydescriptors: 2.1.8 + semver: 5.7.2 + + node-releases@2.0.19: {} + + nodemon@2.0.22: + dependencies: + chokidar: 3.6.0 + debug: 3.2.7(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 5.7.2 + simple-update-notifier: 1.1.0 + supports-color: 5.5.0 + touch: 3.1.1 + undefsafe: 2.0.5 + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.10 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + normalize-path@2.1.1: + dependencies: + remove-trailing-separator: 1.1.0 + + normalize-path@3.0.0: {} + + now-and-later@2.0.1: + dependencies: + once: 1.4.0 + + now-and-later@3.0.0: + dependencies: + once: 1.4.0 + + number-is-nan@1.0.1: {} + + object-assign@4.1.1: {} + + object-copy@0.1.0: + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + + object-inspect@0.4.0: {} + + object-inspect@1.13.3: {} + + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + + object-keys@0.4.0: {} + + object-keys@1.1.1: {} + + object-visit@1.0.1: + dependencies: + isobject: 3.0.1 + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.defaults@1.1.0: + dependencies: + array-each: 1.0.1 + array-slice: 1.1.0 + for-own: 1.0.0 + isobject: 3.0.1 + + object.getownpropertydescriptors@2.1.8: + dependencies: + array.prototype.reduce: 1.0.7 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.0.0 + gopd: 1.2.0 + safe-array-concat: 1.1.3 + + object.map@1.0.1: + dependencies: + for-own: 1.0.0 + make-iterator: 1.0.1 + + object.pick@1.3.0: + dependencies: + isobject: 3.0.1 + + object.reduce@1.0.1: + dependencies: + for-own: 1.0.0 + make-iterator: 1.0.1 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.8.3: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.5 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ordered-read-streams@1.0.1: + dependencies: + readable-stream: 2.3.8 + + os-browserify@0.3.0: {} + + os-locale@1.4.0: + dependencies: + lcid: 1.0.0 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.2.7 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + pako@1.0.11: {} + + pako@2.1.0: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parents@1.0.1: + dependencies: + path-platform: 0.11.15 + + parse-asn1@5.1.7: + dependencies: + asn1.js: 4.10.1 + browserify-aes: 1.2.0 + evp_bytestokey: 1.0.3 + hash-base: 3.0.5 + pbkdf2: 3.1.2 + safe-buffer: 5.2.1 + + parse-filepath@1.0.2: + dependencies: + is-absolute: 1.0.0 + map-cache: 0.2.2 + path-root: 0.1.1 + + parse-json@2.2.0: + dependencies: + error-ex: 1.3.2 + + parse-node-version@1.0.1: {} + + parse-passwd@1.0.0: {} + + parseurl@1.3.3: {} + + pascalcase@0.1.1: {} + + path-browserify@1.0.1: {} + + path-dirname@1.0.2: {} + + path-exists@2.1.0: + dependencies: + pinkie-promise: 2.0.1 + + path-exists@3.0.0: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-platform@0.11.15: {} + + path-root-regex@0.1.2: {} + + path-root@0.1.1: + dependencies: + path-root-regex: 0.1.2 + + path-to-regexp@0.1.12: {} + + path-type@1.1.0: + dependencies: + graceful-fs: 4.2.11 + pify: 2.3.0 + pinkie-promise: 2.0.1 + + pathval@1.1.1: {} + + pbkdf2@3.1.2: + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + peggy@2.0.1: + dependencies: + commander: 9.5.0 + source-map-generator: 0.8.0 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pify@2.3.0: {} + + pify@4.0.1: {} + + pinkie-promise@2.0.1: + dependencies: + pinkie: 2.0.4 + + pinkie@2.0.4: {} + + pirates@4.0.6: {} + + pkg-dir@3.0.0: + dependencies: + find-up: 3.0.0 + + plugin-error@1.0.1: + dependencies: + ansi-colors: 1.1.0 + arr-diff: 4.0.0 + arr-union: 3.1.0 + extend-shallow: 3.0.2 + + plugin-error@2.0.1: + dependencies: + ansi-colors: 1.1.0 + + posix-character-classes@0.1.1: {} + + possible-typed-array-names@1.0.0: {} + + prelude-ls@1.1.2: {} + + prelude-ls@1.2.1: {} + + prettier-plugin-sort-imports@1.8.6(typescript@5.7.3): + dependencies: + prettier: 3.4.2 + typescript: 5.7.3 + + prettier@2.6.2: {} + + prettier@3.4.2: {} + + pretty-hrtime@1.0.3: {} + + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + pstree.remy@1.1.8: {} + + public-encrypt@4.0.3: + dependencies: + bn.js: 4.12.1 + browserify-rsa: 4.1.1 + create-hash: 1.2.0 + parse-asn1: 5.1.7 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + pump@2.0.1: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + pumpify@1.5.1: + dependencies: + duplexify: 3.7.1 + inherits: 2.0.4 + pump: 2.0.1 + + punycode@1.4.1: {} + + punycode@2.3.1: {} + + qs@6.13.0: + dependencies: + side-channel: 1.1.0 + + qs@6.13.1: + dependencies: + side-channel: 1.1.0 + + querystring-es3@0.2.1: {} + + queue-microtask@1.2.3: {} + + queue-tick@1.0.1: {} + + quote-stream@0.0.0: + dependencies: + minimist: 0.0.8 + through2: 0.4.2 + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + randomfill@1.0.4: + dependencies: + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + range-parser@1.2.1: {} + + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + read-only-stream@2.0.0: + dependencies: + readable-stream: 2.3.8 + + read-pkg-up@1.0.1: + dependencies: + find-up: 1.1.2 + read-pkg: 1.1.0 + + read-pkg@1.1.0: + dependencies: + load-json-file: 1.1.0 + normalize-package-data: 2.5.0 + path-type: 1.1.0 + + readable-stream@1.0.34: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + + readable-stream@1.1.14: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@2.2.1: + dependencies: + graceful-fs: 4.2.11 + micromatch: 3.1.10 + readable-stream: 2.3.8 + transitivePeerDependencies: + - supports-color + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + rechoir@0.6.2: + dependencies: + resolve: 1.22.10 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerate-unicode-properties@10.2.0: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regenerator-runtime@0.14.1: {} + + regenerator-transform@0.15.2: + dependencies: + '@babel/runtime': 7.26.0 + + regex-not@1.0.2: + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + regexpu-core@6.2.0: + 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.2.0 + + regjsgen@0.8.0: {} + + regjsparser@0.12.0: + dependencies: + jsesc: 3.0.2 + + remove-bom-buffer@3.0.0: + dependencies: + is-buffer: 1.1.6 + is-utf8: 0.2.1 + + remove-bom-stream@1.2.0: + dependencies: + remove-bom-buffer: 3.0.0 + safe-buffer: 5.2.1 + through2: 2.0.5 + + remove-trailing-separator@1.1.0: {} + + repeat-element@1.1.4: {} + + repeat-string@1.6.1: {} + + replace-ext@1.0.1: {} + + replace-ext@2.0.0: {} + + replace-homedir@1.0.0: + dependencies: + homedir-polyfill: 1.0.3 + is-absolute: 1.0.0 + remove-trailing-separator: 1.1.0 + + require-directory@2.1.1: {} + + require-main-filename@1.0.1: {} + + requires-port@1.0.0: {} + + resolve-dir@1.0.1: + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + + resolve-from@4.0.0: {} + + resolve-options@1.1.0: + dependencies: + value-or-function: 3.0.0 + + resolve-options@2.0.0: + dependencies: + value-or-function: 4.0.0 + + resolve-url@0.2.1: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + ret@0.1.15: {} + + reusify@1.0.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + ripemd160@2.0.2: + dependencies: + hash-base: 3.0.5 + inherits: 2.0.4 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safe-regex@1.1.0: + dependencies: + ret: 0.1.15 + + safer-buffer@2.1.2: {} + + scope-analyzer@2.1.2: + dependencies: + array-from: 2.1.1 + dash-ast: 2.0.1 + es6-map: 0.1.5 + es6-set: 0.1.6 + es6-symbol: 3.1.4 + estree-is-function: 1.0.0 + get-assigned-identifiers: 1.2.0 + + semver-greatest-satisfied-range@1.1.0: + dependencies: + sver-compat: 1.5.0 + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.0.0: {} + + semver@7.6.3: {} + + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + + set-blocking@2.0.0: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.7 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + + set-value@2.0.1: + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + + setprototypeof@1.2.0: {} + + sha.js@2.4.11: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + shallow-clone@3.0.1: + dependencies: + kind-of: 6.0.3 + + shallow-copy@0.0.1: {} + + shasum-object@1.0.0: + dependencies: + fast-safe-stringify: 2.1.1 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.2: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.3 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.3 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + 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 + + simple-concat@1.0.1: {} + + simple-update-notifier@1.1.0: + dependencies: + semver: 7.0.0 + + slash@1.0.0: {} + + snapdragon-node@2.1.1: + dependencies: + define-property: 1.0.0 + isobject: 3.0.1 + snapdragon-util: 3.0.1 + + snapdragon-util@3.0.1: + dependencies: + kind-of: 3.2.2 + + snapdragon@0.8.2: + dependencies: + base: 0.11.2 + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + + source-map-generator@0.8.0: {} + + source-map-resolve@0.5.3: + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-url@0.4.1: {} + + source-map@0.1.43: + dependencies: + amdefine: 1.0.1 + + source-map@0.5.7: {} + + source-map@0.6.1: {} + + source-map@0.7.4: + optional: true + + sourcemap-codec@1.4.8: {} + + sparkles@1.0.1: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.20 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.20 + + spdx-license-ids@3.0.20: {} + + split-string@3.1.0: + dependencies: + extend-shallow: 3.0.2 + + sprintf-js@1.0.3: {} + + sprintf-js@1.1.3: {} + + stack-trace@0.0.10: {} + + static-eval@0.2.4: + dependencies: + escodegen: 0.0.28 + + static-extend@0.1.2: + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + + static-js-yaml@1.0.0: + dependencies: + js-yaml: 3.14.1 + static-module: 1.5.0 + through2: 0.6.5 + + static-module@1.5.0: + dependencies: + concat-stream: 1.6.2 + duplexer2: 0.0.2 + escodegen: 1.3.3 + falafel: 2.2.5 + has: 1.0.4 + object-inspect: 0.4.0 + quote-stream: 0.0.0 + readable-stream: 1.0.34 + shallow-copy: 0.0.1 + static-eval: 0.2.4 + through2: 0.4.2 + + statuses@2.0.1: {} + + stream-browserify@3.0.0: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + + stream-combiner2@1.1.1: + dependencies: + duplexer2: 0.1.4 + readable-stream: 2.3.8 + + stream-combiner@0.2.2: + dependencies: + duplexer: 0.1.2 + through: 2.3.8 + + stream-composer@1.0.2: + dependencies: + streamx: 2.21.1 + + stream-exhaust@1.0.2: {} + + stream-http@3.2.0: + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + + stream-shift@1.0.3: {} + + stream-splicer@2.0.1: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + streamx@2.21.1: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.5.4 + + string-width@1.0.2: + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + strip-ansi: 3.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.0.0 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string_decoder@0.10.31: {} + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@2.0.0: + dependencies: + is-utf8: 0.2.1 + + strip-json-comments@3.1.1: {} + + subarg@1.0.0: + dependencies: + minimist: 1.2.8 + + supports-color@2.0.0: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + sver-compat@1.5.0: + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + + syntax-error@1.4.0: + dependencies: + acorn-node: 1.8.2 + + teex@1.0.1: + dependencies: + streamx: 2.21.1 + + ternary-stream@3.0.0: + dependencies: + duplexify: 4.1.3 + fork-stream: 0.0.4 + merge-stream: 2.0.0 + through2: 3.0.2 + + terser@3.17.0: + dependencies: + acorn: 8.14.0 + commander: 2.20.3 + source-map: 0.6.1 + source-map-support: 0.5.21 + + terser@4.8.1: + dependencies: + acorn: 8.14.0 + commander: 2.20.3 + source-map: 0.6.1 + source-map-support: 0.5.21 + + text-decoder@1.2.3: + dependencies: + b4a: 1.6.7 + + text-table@0.2.0: {} + + through2-filter@3.0.0: + dependencies: + through2: 2.0.5 + xtend: 4.0.2 + + through2@0.4.2: + dependencies: + readable-stream: 1.0.34 + xtend: 2.1.2 + + through2@0.6.5: + dependencies: + readable-stream: 1.0.34 + xtend: 4.0.2 + + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + through2@3.0.2: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + + through2@4.0.2: + dependencies: + readable-stream: 3.6.2 + + through@2.3.8: {} + + time-stamp@1.1.0: {} + + timers-browserify@1.4.2: + dependencies: + process: 0.11.10 + + tiny-lru@11.2.11: {} + + tinyify@3.1.0: + dependencies: + '@goto-bus-stop/envify': 5.0.0 + acorn-node: 1.8.2 + browser-pack-flat: 3.5.0 + bundle-collapser: 1.4.0 + common-shakeify: 1.1.2 + dash-ast: 1.0.0 + minify-stream: 2.1.0 + multisplice: 1.0.0 + through2: 3.0.2 + uglifyify: 5.0.2 + unassertify: 2.1.1 + transitivePeerDependencies: + - supports-color + + to-absolute-glob@2.0.2: + dependencies: + is-absolute: 1.0.0 + is-negated-glob: 1.0.0 + + to-object-path@0.3.0: + dependencies: + kind-of: 3.2.2 + + to-regex-range@2.1.1: + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + to-regex@3.0.2: + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + + to-through@2.0.0: + dependencies: + through2: 2.0.5 + + to-through@3.0.0: + dependencies: + streamx: 2.21.1 + + toidentifier@1.0.1: {} + + touch@3.1.1: {} + + transform-ast@2.4.4: + dependencies: + acorn-node: 1.8.2 + convert-source-map: 1.9.0 + dash-ast: 1.0.0 + is-buffer: 2.0.5 + magic-string: 0.23.2 + merge-source-map: 1.0.4 + nanobench: 2.1.1 + + tty-browserify@0.0.1: {} + + type-check@0.3.2: + dependencies: + prelude-ls: 1.1.2 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.1.0: {} + + type-fest@0.20.2: {} + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + type@2.7.3: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.10 + + typedarray@0.0.6: {} + + typescript@5.7.3: {} + + uglifyify@5.0.2: + dependencies: + convert-source-map: 1.1.3 + minimatch: 3.1.2 + terser: 3.17.0 + through: 2.3.8 + xtend: 4.0.2 + + umd@3.0.3: {} + + unassert@1.6.0: + dependencies: + acorn: 7.4.1 + call-matcher: 2.0.0 + deep-equal: 1.1.2 + espurify: 2.1.1 + estraverse: 4.3.0 + esutils: 2.0.3 + object-assign: 4.1.1 + + unassertify@2.1.1: + dependencies: + acorn: 5.7.4 + convert-source-map: 1.9.0 + escodegen: 1.14.3 + multi-stage-sourcemap: 0.2.1 + through: 2.3.8 + unassert: 1.6.0 + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.3 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + unc-path-regex@0.1.2: {} + + undeclared-identifiers@1.1.3: + dependencies: + acorn-node: 1.8.2 + dash-ast: 1.0.0 + get-assigned-identifiers: 1.2.0 + simple-concat: 1.0.1 + xtend: 4.0.2 + + undefsafe@2.0.5: {} + + undertaker-registry@1.0.1: {} + + undertaker@1.3.0: + dependencies: + arr-flatten: 1.1.0 + arr-map: 2.0.2 + bach: 1.2.0 + collection-map: 1.0.0 + es6-weak-map: 2.0.3 + fast-levenshtein: 1.1.4 + last-run: 1.1.1 + object.defaults: 1.1.0 + object.reduce: 1.0.1 + undertaker-registry: 1.0.1 + + undici-types@6.20.0: {} + + undici@7.4.0: {} + + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.1.0 + + unicode-match-property-value-ecmascript@2.2.0: {} + + unicode-property-aliases-ecmascript@2.1.0: {} + + union-value@1.0.1: + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + + unique-stream@2.3.1: + dependencies: + json-stable-stringify-without-jsonify: 1.0.1 + through2-filter: 3.0.0 + + unpipe@1.0.0: {} + + unset-value@1.0.0: + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + + upath@1.2.0: {} + + update-browserslist-db@1.1.2(browserslist@4.24.4): + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + urix@0.1.0: {} + + url@0.11.4: + dependencies: + punycode: 1.4.1 + qs: 6.13.1 + + use@3.1.1: {} + + util-deprecate@1.0.2: {} + + util@0.10.4: + dependencies: + inherits: 2.0.3 + + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.1.0 + is-typed-array: 1.1.15 + which-typed-array: 1.1.18 + + utils-merge@1.0.1: {} + + uuid@3.4.0: {} + + v8flags@3.2.0: + dependencies: + homedir-polyfill: 1.0.3 + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + value-or-function@3.0.0: {} + + value-or-function@4.0.0: {} + + vary@1.1.2: {} + + verror@1.10.0: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + + vinyl-contents@2.0.0: + dependencies: + bl: 5.1.0 + vinyl: 3.0.0 + + vinyl-fs@3.0.3: + dependencies: + fs-mkdirp-stream: 1.0.0 + glob-stream: 6.1.0 + graceful-fs: 4.2.11 + is-valid-glob: 1.0.0 + lazystream: 1.0.1 + lead: 1.0.0 + object.assign: 4.1.7 + pumpify: 1.5.1 + readable-stream: 2.3.8 + remove-bom-buffer: 3.0.0 + remove-bom-stream: 1.2.0 + resolve-options: 1.1.0 + through2: 2.0.5 + to-through: 2.0.0 + value-or-function: 3.0.0 + vinyl: 2.2.1 + vinyl-sourcemap: 1.1.0 + + vinyl-fs@4.0.0: + dependencies: + fs-mkdirp-stream: 2.0.1 + glob-stream: 8.0.2 + graceful-fs: 4.2.11 + iconv-lite: 0.6.3 + is-valid-glob: 1.0.0 + lead: 4.0.0 + normalize-path: 3.0.0 + resolve-options: 2.0.0 + stream-composer: 1.0.2 + streamx: 2.21.1 + to-through: 3.0.0 + value-or-function: 4.0.0 + vinyl: 3.0.0 + vinyl-sourcemap: 2.0.0 + + vinyl-sourcemap@1.1.0: + dependencies: + append-buffer: 1.0.2 + convert-source-map: 1.9.0 + graceful-fs: 4.2.11 + normalize-path: 2.1.1 + now-and-later: 2.0.1 + remove-bom-buffer: 3.0.0 + vinyl: 2.2.1 + + vinyl-sourcemap@2.0.0: + dependencies: + convert-source-map: 2.0.0 + graceful-fs: 4.2.11 + now-and-later: 3.0.0 + streamx: 2.21.1 + vinyl: 3.0.0 + vinyl-contents: 2.0.0 + + vinyl-sourcemaps-apply@0.2.1: + dependencies: + source-map: 0.5.7 + + vinyl@2.2.1: + dependencies: + clone: 2.1.2 + clone-buffer: 1.0.0 + clone-stats: 1.0.0 + cloneable-readable: 1.1.3 + remove-trailing-separator: 1.1.0 + replace-ext: 1.0.1 + + vinyl@3.0.0: + dependencies: + clone: 2.1.2 + clone-stats: 1.0.0 + remove-trailing-separator: 1.1.0 + replace-ext: 2.0.0 + teex: 1.0.1 + + vm-browserify@1.1.2: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.1 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.3 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.0 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 + is-regex: 1.2.1 + is-weakref: 1.1.0 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.18 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-module@1.0.0: {} + + which-typed-array@1.1.18: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + for-each: 0.3.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + workerpool@6.5.1: {} + + wrap-ansi@2.1.0: + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-comment@1.0.1: {} + + wrappy@1.0.2: {} + + xtend@2.1.2: + dependencies: + object-keys: 0.4.0 + + xtend@4.0.2: {} + + y18n@3.2.2: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yargs-parser@20.2.9: {} + + yargs-parser@5.0.1: + dependencies: + camelcase: 3.0.0 + object.assign: 4.1.7 + + yargs-unparser@2.0.0: + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yargs@7.1.2: + dependencies: + camelcase: 3.0.0 + cliui: 3.2.0 + decamelize: 1.2.0 + get-caller-file: 1.0.3 + os-locale: 1.4.0 + read-pkg-up: 1.0.1 + require-directory: 2.1.1 + require-main-filename: 1.0.1 + set-blocking: 2.0.0 + string-width: 1.0.2 + which-module: 1.0.0 + y18n: 3.2.2 + yargs-parser: 5.0.1 + + yocto-queue@0.1.0: {} diff --git a/backend/src/constants.js b/backend/src/constants.js new file mode 100644 index 0000000000..d832a25674 --- /dev/null +++ b/backend/src/constants.js @@ -0,0 +1,18 @@ +export const SCHEMA_VERSION_KEY = 'schemaVersion'; +export const SETTINGS_KEY = 'settings'; +export const SUBS_KEY = 'subs'; +export const COLLECTIONS_KEY = 'collections'; +export const FILES_KEY = 'files'; +export const MODULES_KEY = 'modules'; +export const ARTIFACTS_KEY = 'artifacts'; +export const RULES_KEY = 'rules'; +export const TOKENS_KEY = 'tokens'; +export const GIST_BACKUP_KEY = 'Auto Generated Sub-Store Backup'; +export const GIST_BACKUP_FILE_NAME = 'Sub-Store'; +export const ARTIFACT_REPOSITORY_KEY = 'Sub-Store Artifacts Repository'; +export const RESOURCE_CACHE_KEY = '#sub-store-cached-resource'; +export const HEADERS_RESOURCE_CACHE_KEY = '#sub-store-cached-headers-resource'; +export const CHR_EXPIRATION_TIME_KEY = '#sub-store-chr-expiration-time'; // Custom expiration time key; (Loon|Surge) Default write 1 min +export const CACHE_EXPIRATION_TIME_MS = 60 * 60 * 1000; // 1 hour +export const SCRIPT_RESOURCE_CACHE_KEY = '#sub-store-cached-script-resource'; // cached-script-resource CSR +export const CSR_EXPIRATION_TIME_KEY = '#sub-store-csr-expiration-time'; // Custom expiration time key; (Loon|Surge) Default write 48 hour diff --git a/backend/src/core/app.js b/backend/src/core/app.js new file mode 100644 index 0000000000..08517b6047 --- /dev/null +++ b/backend/src/core/app.js @@ -0,0 +1,4 @@ +import { OpenAPI } from '@/vendor/open-api'; + +const $ = new OpenAPI('sub-store'); +export default $; diff --git a/backend/src/core/proxy-utils/index.js b/backend/src/core/proxy-utils/index.js new file mode 100644 index 0000000000..91218ecdb7 --- /dev/null +++ b/backend/src/core/proxy-utils/index.js @@ -0,0 +1,637 @@ +import { Buffer } from 'buffer'; +import rs from '@/utils/rs'; +import YAML from '@/utils/yaml'; +import download, { downloadFile } from '@/utils/download'; +import { + isIPv4, + isIPv6, + isValidPortNumber, + isValidUUID, + isNotBlank, + ipAddress, + getRandomPort, + numberToString, +} from '@/utils'; +import PROXY_PROCESSORS, { ApplyProcessor } from './processors'; +import PROXY_PREPROCESSORS from './preprocessors'; +import PROXY_PRODUCERS from './producers'; +import PROXY_PARSERS from './parsers'; +import $ from '@/core/app'; +import { FILES_KEY, MODULES_KEY } from '@/constants'; +import { findByName } from '@/utils/database'; +import { produceArtifact } from '@/restful/sync'; +import { getFlag, removeFlag, getISO, MMDB } from '@/utils/geo'; +import Gist from '@/utils/gist'; +import { isPresent } from './producers/utils'; +import { doh } from '@/utils/dns'; + +function preprocess(raw) { + for (const processor of PROXY_PREPROCESSORS) { + try { + if (processor.test(raw)) { + $.info(`Pre-processor [${processor.name}] activated`); + return processor.parse(raw); + } + } catch (e) { + $.error(`Parser [${processor.name}] failed\n Reason: ${e}`); + } + } + return raw; +} + +function parse(raw) { + raw = preprocess(raw); + // parse + const lines = raw.split('\n'); + const proxies = []; + let lastParser; + + for (let line of lines) { + line = line.trim(); + if (line.length === 0) continue; // skip empty line + let success = false; + + // try to parse with last used parser + if (lastParser) { + const [proxy, error] = tryParse(lastParser, line); + if (!error) { + proxies.push(lastParse(proxy)); + success = true; + } + } + + if (!success) { + // search for a new parser + for (const parser of PROXY_PARSERS) { + const [proxy, error] = tryParse(parser, line); + if (!error) { + proxies.push(lastParse(proxy)); + lastParser = parser; + success = true; + $.info(`${parser.name} is activated`); + break; + } + } + } + + if (!success) { + $.error(`Failed to parse line: ${line}`); + } + } + return proxies.filter((proxy) => { + if (['vless', 'vmess'].includes(proxy.type)) { + const isProxyUUIDValid = isValidUUID(proxy.uuid); + if (!isProxyUUIDValid) { + $.error(`UUID may be invalid: ${proxy.name} ${proxy.uuid}`); + } + // return isProxyUUIDValid; + } + return true; + }); +} + +async function processFn( + proxies, + operators = [], + targetPlatform, + source, + $options, +) { + for (const item of operators) { + if (item.disabled) { + $.log( + `Skipping disabled operator: "${ + item.type + }" with arguments:\n >>> ${ + JSON.stringify(item.args, null, 2) || 'None' + }`, + ); + continue; + } + // process script + let script; + let $arguments = {}; + if (item.type.indexOf('Script') !== -1) { + const { mode, content } = item.args; + if (mode === 'link') { + let url = content || ''; + // extract link arguments + const rawArgs = url.split('#'); + if (rawArgs.length > 1) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $arguments = JSON.parse(decodeURIComponent(rawArgs[1])); + } catch (e) { + for (const pair of rawArgs[1].split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $arguments[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + } + url = `${url.split('#')[0]}${ + rawArgs[2] + ? `#${rawArgs[2]}` + : $arguments?.noCache != null || + $arguments?.insecure != null + ? `#${rawArgs[1]}` + : '' + }`; + const downloadUrlMatch = url.match( + /^\/api\/(file|module)\/(.+)/, + ); + if (downloadUrlMatch) { + let type = ''; + try { + type = downloadUrlMatch?.[1]; + let name = downloadUrlMatch?.[2]; + if (name == null) { + throw new Error(`本地 ${type} URL 无效: ${url}`); + } + name = decodeURIComponent(name); + const key = type === 'module' ? MODULES_KEY : FILES_KEY; + const item = findByName($.read(key), name); + if (!item) { + throw new Error(`找不到 ${type}: ${name}`); + } + + if (type === 'module') { + script = item.content; + } else { + script = await produceArtifact({ + type: 'file', + name, + }); + } + } catch (err) { + $.error( + `Error when loading ${type}: ${item.args.content}.\n Reason: ${err}`, + ); + throw new Error(`无法加载 ${type}: ${url}`); + } + } else { + // if this is a remote script, download it + try { + script = await download(url); + // $.info(`Script loaded: >>>\n ${script}`); + } catch (err) { + $.error( + `Error when downloading remote script: ${item.args.content}.\n Reason: ${err}`, + ); + throw new Error(`无法下载脚本: ${url}`); + } + } + } else { + script = content; + $arguments = item.args.arguments || {}; + } + } + + if (!PROXY_PROCESSORS[item.type]) { + $.error(`Unknown operator: "${item.type}"`); + continue; + } + + $.log( + `Applying "${item.type}" with arguments:\n >>> ${ + JSON.stringify(item.args, null, 2) || 'None' + }`, + ); + let processor; + if (item.type.indexOf('Script') !== -1) { + processor = PROXY_PROCESSORS[item.type]( + script, + targetPlatform, + $arguments, + source, + $options, + ); + } else { + processor = PROXY_PROCESSORS[item.type](item.args || {}); + } + proxies = await ApplyProcessor(processor, proxies); + } + return proxies; +} + +function produce(proxies, targetPlatform, type, opts = {}) { + const producer = PROXY_PRODUCERS[targetPlatform]; + if (!producer) { + throw new Error(`Target platform: ${targetPlatform} is not supported!`); + } + + const sni_off_supported = /Surge|SurgeMac|Shadowrocket/i.test( + targetPlatform, + ); + + // filter unsupported proxies + proxies = proxies.filter((proxy) => { + // 检查代理是否支持目标平台 + if (proxy.supported && proxy.supported[targetPlatform] === false) { + return false; + } + + // 对于 vless 和 vmess 代理,需要额外验证 UUID + if (['vless', 'vmess'].includes(proxy.type)) { + const isProxyUUIDValid = isValidUUID(proxy.uuid); + if (!isProxyUUIDValid) + $.error(`UUID may be invalid: ${proxy.name} ${proxy.uuid}`); + // return isProxyUUIDValid; + } + + return true; + }); + + proxies = proxies.map((proxy) => { + proxy._resolved = proxy.resolved; + + if (!isNotBlank(proxy.name)) { + proxy.name = `${proxy.type} ${proxy.server}:${proxy.port}`; + } + if (proxy['disable-sni']) { + if (sni_off_supported) { + proxy.sni = 'off'; + } else if (!['tuic'].includes(proxy.type)) { + $.error( + `Target platform ${targetPlatform} does not support sni off. Proxy's fields (sni, tls-fingerprint and skip-cert-verify) will be modified.`, + ); + proxy.sni = ''; + proxy['skip-cert-verify'] = true; + delete proxy['tls-fingerprint']; + } + } + + // 处理 端口跳跃 + if (proxy.ports) { + proxy.ports = String(proxy.ports); + if (!['ClashMeta'].includes(targetPlatform)) { + proxy.ports = proxy.ports.replace(/\//g, ','); + } + if (!proxy.port) { + proxy.port = getRandomPort(proxy.ports); + } + } + + return proxy; + }); + + $.log(`Producing proxies for target: ${targetPlatform}`); + if (typeof producer.type === 'undefined' || producer.type === 'SINGLE') { + let list = proxies + .map((proxy) => { + try { + return producer.produce(proxy, type, opts); + } catch (err) { + $.error( + `Cannot produce proxy: ${JSON.stringify( + proxy, + null, + 2, + )}\nReason: ${err}`, + ); + return ''; + } + }) + .filter((line) => line.length > 0); + list = type === 'internal' ? list : list.join('\n'); + if ( + targetPlatform.startsWith('Surge') && + proxies.length > 0 && + proxies.every((p) => p.type === 'wireguard') + ) { + list = `#!name=${proxies[0]?._subName} +#!desc=${proxies[0]?._desc ?? ''} +#!category=${proxies[0]?._category ?? ''} +${list}`; + } + return list; + } else if (producer.type === 'ALL') { + return producer.produce(proxies, type, opts); + } +} + +export const ProxyUtils = { + parse, + process: processFn, + produce, + ipAddress, + getRandomPort, + isIPv4, + isIPv6, + isIP, + yaml: YAML, + getFlag, + removeFlag, + getISO, + MMDB, + Gist, + download, + downloadFile, + isValidUUID, + doh, +}; + +function tryParse(parser, line) { + if (!safeMatch(parser, line)) return [null, new Error('Parser mismatch')]; + try { + const proxy = parser.parse(line); + return [proxy, null]; + } catch (err) { + return [null, err]; + } +} + +function safeMatch(parser, line) { + try { + return parser.test(line); + } catch (err) { + return false; + } +} + +function formatTransportPath(path) { + if (typeof path === 'string' || typeof path === 'number') { + path = String(path).trim(); + + if (path === '') { + return '/'; + } else if (!path.startsWith('/')) { + return '/' + path; + } + } + return path; +} + +function lastParse(proxy) { + if (typeof proxy.cipher === 'string') { + proxy.cipher = proxy.cipher.toLowerCase(); + } + if (typeof proxy.password === 'number') { + proxy.password = numberToString(proxy.password); + } + if ( + ['ss'].includes(proxy.type) && + proxy.cipher === 'none' && + !proxy.password + ) { + // https://github.com/MetaCubeX/mihomo/issues/1677 + proxy.password = ''; + } + if (proxy.interface) { + proxy['interface-name'] = proxy.interface; + delete proxy.interface; + } + if (isValidPortNumber(proxy.port)) { + proxy.port = parseInt(proxy.port, 10); + } + if (proxy.server) { + proxy.server = `${proxy.server}` + .trim() + .replace(/^\[/, '') + .replace(/\]$/, ''); + } + if (proxy.network === 'ws') { + if (!proxy['ws-opts'] && (proxy['ws-path'] || proxy['ws-headers'])) { + proxy['ws-opts'] = {}; + if (proxy['ws-path']) { + proxy['ws-opts'].path = proxy['ws-path']; + } + if (proxy['ws-headers']) { + proxy['ws-opts'].headers = proxy['ws-headers']; + } + } + delete proxy['ws-path']; + delete proxy['ws-headers']; + } + + const transportPath = proxy[`${proxy.network}-opts`]?.path; + + if (Array.isArray(transportPath)) { + proxy[`${proxy.network}-opts`].path = transportPath.map((item) => + formatTransportPath(item), + ); + } else if (transportPath != null) { + proxy[`${proxy.network}-opts`].path = + formatTransportPath(transportPath); + } + + if (proxy.type === 'trojan') { + if (proxy.network === 'tcp') { + delete proxy.network; + } + } + if (['vless'].includes(proxy.type)) { + if (!proxy.network) { + proxy.network = 'tcp'; + } + } + if ( + [ + 'trojan', + 'tuic', + 'hysteria', + 'hysteria2', + 'juicity', + 'anytls', + ].includes(proxy.type) + ) { + proxy.tls = true; + } + if (proxy.network) { + let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; + let transporthost = proxy[`${proxy.network}-opts`]?.headers?.host; + if (proxy.network === 'h2') { + if (!transporthost && transportHost) { + proxy[`${proxy.network}-opts`].headers.host = transportHost; + delete proxy[`${proxy.network}-opts`].headers.Host; + } + } else if (transporthost && !transportHost) { + proxy[`${proxy.network}-opts`].headers.Host = transporthost; + delete proxy[`${proxy.network}-opts`].headers.host; + } + } + if (proxy.network === 'h2') { + const host = proxy['h2-opts']?.headers?.host; + const path = proxy['h2-opts']?.path; + if (host && !Array.isArray(host)) { + proxy['h2-opts'].headers.host = [host]; + } + if (Array.isArray(path)) { + proxy['h2-opts'].path = path[0]; + } + } + + // 非 tls, 有 ws/http 传输层, 使用域名的节点, 将设置传输层 Host 防止之后域名解析后丢失域名(不覆盖现有的 Host) + if ( + !proxy.tls && + ['ws', 'http'].includes(proxy.network) && + !proxy[`${proxy.network}-opts`]?.headers?.Host && + !isIP(proxy.server) + ) { + proxy[`${proxy.network}-opts`] = proxy[`${proxy.network}-opts`] || {}; + proxy[`${proxy.network}-opts`].headers = + proxy[`${proxy.network}-opts`].headers || {}; + proxy[`${proxy.network}-opts`].headers.Host = + ['vmess', 'vless'].includes(proxy.type) && proxy.network === 'http' + ? [proxy.server] + : proxy.server; + } + // 统一将 VMess 和 VLESS 的 http 传输层的 path 和 Host 处理为数组 + if (['vmess', 'vless'].includes(proxy.type) && proxy.network === 'http') { + let transportPath = proxy[`${proxy.network}-opts`]?.path; + let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; + if (transportHost && !Array.isArray(transportHost)) { + proxy[`${proxy.network}-opts`].headers.Host = [transportHost]; + } + if (transportPath && !Array.isArray(transportPath)) { + proxy[`${proxy.network}-opts`].path = [transportPath]; + } + } + if (proxy.tls && !proxy.sni) { + if (!isIP(proxy.server)) { + proxy.sni = proxy.server; + } + if (!proxy.sni && proxy.network) { + let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; + transportHost = Array.isArray(transportHost) + ? transportHost[0] + : transportHost; + if (transportHost) { + proxy.sni = transportHost; + } + } + } + // if (['hysteria', 'hysteria2', 'tuic'].includes(proxy.type)) { + if (proxy.ports) { + proxy.ports = String(proxy.ports).replace(/\//g, ','); + } else { + delete proxy.ports; + } + // } + if ( + ['hysteria2'].includes(proxy.type) && + proxy.obfs && + !['salamander'].includes(proxy.obfs) && + !proxy['obfs-password'] + ) { + proxy['obfs-password'] = proxy.obfs; + proxy.obfs = 'salamander'; + } + if ( + ['hysteria2'].includes(proxy.type) && + !proxy['obfs-password'] && + proxy['obfs_password'] + ) { + proxy['obfs-password'] = proxy['obfs_password']; + delete proxy['obfs_password']; + } + if (['vless'].includes(proxy.type)) { + // 删除 reality-opts: {} + if ( + proxy['reality-opts'] && + Object.keys(proxy['reality-opts']).length === 0 + ) { + delete proxy['reality-opts']; + } + // 删除 grpc-opts: {} + if ( + proxy['grpc-opts'] && + Object.keys(proxy['grpc-opts']).length === 0 + ) { + delete proxy['grpc-opts']; + } + // 非 reality, 空 flow 没有意义 + if (!proxy['reality-opts'] && !proxy.flow) { + delete proxy.flow; + } + if (['http'].includes(proxy.network)) { + let transportPath = proxy[`${proxy.network}-opts`]?.path; + if (!transportPath) { + if (!proxy[`${proxy.network}-opts`]) { + proxy[`${proxy.network}-opts`] = {}; + } + proxy[`${proxy.network}-opts`].path = ['/']; + } + } + } + + if (typeof proxy.name !== 'string') { + if (/^\d+$/.test(proxy.name)) { + proxy.name = `${proxy.name}`; + } else { + try { + if (proxy.name?.data) { + proxy.name = Buffer.from(proxy.name.data).toString('utf8'); + } else { + proxy.name = Buffer.from(proxy.name).toString('utf8'); + } + } catch (e) { + $.error(`proxy.name decode failed\nReason: ${e}`); + proxy.name = `${proxy.type} ${proxy.server}:${proxy.port}`; + } + } + } + if (['ws', 'http', 'h2'].includes(proxy.network)) { + if ( + ['ws', 'h2'].includes(proxy.network) && + !proxy[`${proxy.network}-opts`]?.path + ) { + proxy[`${proxy.network}-opts`] = + proxy[`${proxy.network}-opts`] || {}; + proxy[`${proxy.network}-opts`].path = '/'; + } else if ( + proxy.network === 'http' && + (!Array.isArray(proxy[`${proxy.network}-opts`]?.path) || + proxy[`${proxy.network}-opts`]?.path.every((i) => !i)) + ) { + proxy[`${proxy.network}-opts`] = + proxy[`${proxy.network}-opts`] || {}; + proxy[`${proxy.network}-opts`].path = ['/']; + } + } + if (['', 'off'].includes(proxy.sni)) { + proxy['disable-sni'] = true; + } + let caStr = proxy['ca_str']; + if (proxy['ca-str']) { + caStr = proxy['ca-str']; + } else if (caStr) { + delete proxy['ca_str']; + proxy['ca-str'] = caStr; + } + try { + if ($.env.isNode && !caStr && proxy['_ca']) { + caStr = $.node.fs.readFileSync(proxy['_ca'], { + encoding: 'utf8', + }); + } + } catch (e) { + $.error(`Read ca file failed\nReason: ${e}`); + } + if (!proxy['tls-fingerprint'] && caStr) { + proxy['tls-fingerprint'] = rs.generateFingerprint(caStr); + } + if ( + ['ss'].includes(proxy.type) && + isPresent(proxy, 'shadow-tls-password') + ) { + proxy.plugin = 'shadow-tls'; + proxy['plugin-opts'] = { + host: proxy['shadow-tls-sni'], + password: proxy['shadow-tls-password'], + version: proxy['shadow-tls-version'], + }; + delete proxy['shadow-tls-sni']; + delete proxy['shadow-tls-password']; + delete proxy['shadow-tls-version']; + } + return proxy; +} + +function isIP(ip) { + return isIPv4(ip) || isIPv6(ip); +} diff --git a/backend/src/core/proxy-utils/parsers/index.js b/backend/src/core/proxy-utils/parsers/index.js new file mode 100644 index 0000000000..b2fa24d27d --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/index.js @@ -0,0 +1,1656 @@ +import { + isIPv4, + isIPv6, + getIfNotBlank, + isPresent, + isNotBlank, + getIfPresent, + getRandomPort, +} from '@/utils'; +import getSurgeParser from './peggy/surge'; +import getLoonParser from './peggy/loon'; +import getQXParser from './peggy/qx'; +import getTrojanURIParser from './peggy/trojan-uri'; +import $ from '@/core/app'; + +import { Base64 } from 'js-base64'; + +function surge_port_hopping(raw) { + const [parts, port_hopping] = + raw.match( + /,\s*?port-hopping\s*?=\s*?["']?\s*?((\d+(-\d+)?)([,;]\d+(-\d+)?)*)\s*?["']?\s*?/, + ) || []; + return { + port_hopping: port_hopping + ? port_hopping.replace(/;/g, ',') + : undefined, + line: parts ? raw.replace(parts, '') : raw, + }; +} + +function URI_PROXY() { + // socks5+tls + // socks5 + // http, https(可以这么写) + const name = 'URI PROXY Parser'; + const test = (line) => { + return /^(socks5\+tls|socks5|http|https):\/\//.test(line); + }; + const parse = (line) => { + // parse url + // eslint-disable-next-line no-unused-vars + let [__, type, tls, username, password, server, port, query, name] = + line.match( + /^(socks5|http|http)(\+tls|s)?:\/\/(?:(.*?):(.*?)@)?(.*?)(?::(\d+?))?(\?.*?)?(?:#(.*?))?$/, + ); + if (port) { + port = parseInt(port, 10); + } else { + if (tls) { + port = 443; + } else if (type === 'http') { + port = 80; + } else { + $.error(`port is not present in line: ${line}`); + throw new Error(`port is not present in line: ${line}`); + } + $.info(`port is not present in line: ${line}, set to ${port}`); + } + + const proxy = { + name: + name != null + ? decodeURIComponent(name) + : `${type} ${server}:${port}`, + type, + tls: tls ? true : false, + server, + port, + username: + username != null ? decodeURIComponent(username) : undefined, + password: + password != null ? decodeURIComponent(password) : undefined, + }; + + return proxy; + }; + return { name, test, parse }; +} +function URI_SOCKS() { + const name = 'URI SOCKS Parser'; + const test = (line) => { + return /^socks:\/\//.test(line); + }; + const parse = (line) => { + // parse url + // eslint-disable-next-line no-unused-vars + let [__, type, auth, server, port, query, name] = line.match( + /^(socks)?:\/\/(?:(.*)@)?(.*?)(?::(\d+?))?(\?.*?)?(?:#(.*?))?$/, + ); + if (port) { + port = parseInt(port, 10); + } else { + $.error(`port is not present in line: ${line}`); + throw new Error(`port is not present in line: ${line}`); + } + let username, password; + if (auth) { + const parsed = Base64.decode(decodeURIComponent(auth)).split(':'); + username = parsed[0]; + password = parsed[1]; + } + + const proxy = { + name: + name != null + ? decodeURIComponent(name) + : `${type} ${server}:${port}`, + type: 'socks5', + server, + port, + username, + password, + }; + + return proxy; + }; + return { name, test, parse }; +} +// Parse SS URI format (only supports new SIP002, legacy format is depreciated). +// reference: https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme +function URI_SS() { + // TODO: 暂不支持 httpupgrade + const name = 'URI SS Parser'; + const test = (line) => { + return /^ss:\/\//.test(line); + }; + const parse = (line) => { + // parse url + let content = line.split('ss://')[1]; + + let name = line.split('#')[1]; + const proxy = { + type: 'ss', + }; + content = content.split('#')[0]; // strip proxy name + // handle IPV4 and IPV6 + let serverAndPortArray = content.match(/@([^/]*)(\/|$)/); + + let rawUserInfoStr = decodeURIComponent(content.split('@')[0]); // 其实应该分隔之后, 用户名和密码再 decodeURIComponent. 但是问题不大 + let userInfoStr; + if (rawUserInfoStr?.startsWith('2022-blake3-')) { + userInfoStr = rawUserInfoStr; + } else { + userInfoStr = Base64.decode(rawUserInfoStr); + } + + let query = ''; + if (!serverAndPortArray) { + if (content.includes('?')) { + const parsed = content.match(/^(.*)(\?.*)$/); + content = parsed[1]; + query = parsed[2]; + } + content = Base64.decode(content); + + if (query) { + if (/(&|\?)v2ray-plugin=/.test(query)) { + const parsed = query.match(/(&|\?)v2ray-plugin=(.*?)(&|$)/); + let v2rayPlugin = parsed[2]; + if (v2rayPlugin) { + proxy.plugin = 'v2ray-plugin'; + proxy['plugin-opts'] = JSON.parse( + Base64.decode(v2rayPlugin), + ); + } + } + content = `${content}${query}`; + } + userInfoStr = content.match(/(^.*)@/)?.[1]; + serverAndPortArray = content.match(/@([^/@]*)(\/|$)/); + } else if (content.includes('?')) { + const parsed = content.match(/(\?.*)$/); + query = parsed[1]; + } + + const serverAndPort = serverAndPortArray[1]; + const portIdx = serverAndPort.lastIndexOf(':'); + proxy.server = serverAndPort.substring(0, portIdx); + proxy.port = `${serverAndPort.substring(portIdx + 1)}`.match( + /\d+/, + )?.[0]; + let userInfo = userInfoStr.match(/(^.*?):(.*$)/); + proxy.cipher = userInfo?.[1]; + proxy.password = userInfo?.[2]; + // if (!proxy.cipher || !proxy.password) { + // userInfo = rawUserInfoStr.match(/(^.*?):(.*$)/); + // proxy.cipher = userInfo?.[1]; + // proxy.password = userInfo?.[2]; + // } + + // handle obfs + const pluginMatch = content.match(/[?&]plugin=([^&]+)/); + const shadowTlsMatch = content.match(/[?&]shadow-tls=([^&]+)/); + + if (pluginMatch) { + const pluginInfo = ( + 'plugin=' + decodeURIComponent(pluginMatch[1]) + ).split(';'); + const params = {}; + for (const item of pluginInfo) { + const [key, val] = item.split('='); + if (key) params[key] = val || true; // some options like "tls" will not have value + } + switch (params.plugin) { + case 'obfs-local': + case 'simple-obfs': + proxy.plugin = 'obfs'; + proxy['plugin-opts'] = { + mode: params.obfs, + host: getIfNotBlank(params['obfs-host']), + }; + break; + case 'v2ray-plugin': + proxy.plugin = 'v2ray-plugin'; + proxy['plugin-opts'] = { + mode: 'websocket', + host: getIfNotBlank(params['obfs-host']), + path: getIfNotBlank(params.path), + tls: getIfPresent(params.tls), + }; + break; + case 'shadow-tls': { + proxy.plugin = 'shadow-tls'; + const version = getIfNotBlank(params['version']); + proxy['plugin-opts'] = { + host: getIfNotBlank(params['host']), + password: getIfNotBlank(params['password']), + version: version ? parseInt(version, 10) : undefined, + }; + break; + } + default: + throw new Error( + `Unsupported plugin option: ${params.plugin}`, + ); + } + } + // Shadowrocket + if (shadowTlsMatch) { + const params = JSON.parse(Base64.decode(shadowTlsMatch[1])); + const version = getIfNotBlank(params['version']); + const address = getIfNotBlank(params['address']); + const port = getIfNotBlank(params['port']); + proxy.plugin = 'shadow-tls'; + proxy['plugin-opts'] = { + host: getIfNotBlank(params['host']), + password: getIfNotBlank(params['password']), + version: version ? parseInt(version, 10) : undefined, + }; + if (address) { + proxy.server = address; + } + if (port) { + proxy.port = parseInt(port, 10); + } + } + if (/(&|\?)uot=(1|true)/i.test(query)) { + proxy['udp-over-tcp'] = true; + } + if (/(&|\?)tfo=(1|true)/i.test(query)) { + proxy.tfo = true; + } + if (name != null) { + name = decodeURIComponent(name); + } + proxy.name = name ?? `SS ${proxy.server}:${proxy.port}`; + return proxy; + }; + return { name, test, parse }; +} + +// Parse URI SSR format, such as ssr://xxx +function URI_SSR() { + const name = 'URI SSR Parser'; + const test = (line) => { + return /^ssr:\/\//.test(line); + }; + const parse = (line) => { + line = Base64.decode(line.split('ssr://')[1]); + + // handle IPV6 & IPV4 format + let splitIdx = line.indexOf(':origin'); + if (splitIdx === -1) { + splitIdx = line.indexOf(':auth_'); + } + const serverAndPort = line.substring(0, splitIdx); + const server = serverAndPort.substring( + 0, + serverAndPort.lastIndexOf(':'), + ); + const port = serverAndPort.substring( + serverAndPort.lastIndexOf(':') + 1, + ); + + let params = line + .substring(splitIdx + 1) + .split('/?')[0] + .split(':'); + let proxy = { + type: 'ssr', + server, + port, + protocol: params[0], + cipher: params[1], + obfs: params[2], + password: Base64.decode(params[3]), + }; + // get other params + const other_params = {}; + line = line.split('/?')[1].split('&'); + if (line.length > 1) { + for (const item of line) { + let [key, val] = item.split('='); + val = val.trim(); + if (val.length > 0 && val !== '(null)') { + other_params[key] = val; + } + } + } + proxy = { + ...proxy, + name: other_params.remarks + ? Base64.decode(other_params.remarks) + : proxy.server, + 'protocol-param': getIfNotBlank( + Base64.decode(other_params.protoparam || '').replace(/\s/g, ''), + ), + 'obfs-param': getIfNotBlank( + Base64.decode(other_params.obfsparam || '').replace(/\s/g, ''), + ), + }; + return proxy; + }; + + return { name, test, parse }; +} + +// V2rayN URI VMess format +// reference: https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2) + +// Quantumult VMess format +function URI_VMess() { + const name = 'URI VMess Parser'; + const test = (line) => { + return /^vmess:\/\//.test(line); + }; + const parse = (line) => { + line = line.split('vmess://')[1]; + let content = Base64.decode(line.replace(/\?.*?$/, '')); + if (/=\s*vmess/.test(content)) { + // Quantumult VMess URI format + const partitions = content.split(',').map((p) => p.trim()); + // get keyword params + const params = {}; + for (const part of partitions) { + if (part.indexOf('=') !== -1) { + const [key, val] = part.split('='); + params[key.trim()] = val.trim(); + } + } + + const proxy = { + name: partitions[0].split('=')[0].trim(), + type: 'vmess', + server: partitions[1], + port: partitions[2], + cipher: getIfNotBlank(partitions[3], 'auto'), + uuid: partitions[4].match(/^"(.*)"$/)[1], + tls: params.obfs === 'wss', + udp: getIfPresent(params['udp-relay']), + tfo: getIfPresent(params['fast-open']), + 'skip-cert-verify': isPresent(params['tls-verification']) + ? !params['tls-verification'] + : undefined, + }; + + // handle ws headers + if (isPresent(params.obfs)) { + if (params.obfs === 'ws' || params.obfs === 'wss') { + proxy.network = 'ws'; + proxy['ws-opts'].path = ( + getIfNotBlank(params['obfs-path']) || '"/"' + ).match(/^"(.*)"$/)[1]; + let obfs_host = params['obfs-header']; + if (obfs_host && obfs_host.indexOf('Host') !== -1) { + obfs_host = obfs_host.match( + /Host:\s*([a-zA-Z0-9-.]*)/, + )[1]; + } + if (isNotBlank(obfs_host)) { + proxy['ws-opts'].headers = { + Host: obfs_host, + }; + } + } else { + throw new Error(`Unsupported obfs: ${params.obfs}`); + } + } + return proxy; + } else { + let params = {}; + + try { + // V2rayN URI format + params = JSON.parse(content); + } catch (e) { + // Shadowrocket URI format + // eslint-disable-next-line no-unused-vars + let [__, base64Line, qs] = /(^[^?]+?)\/?\?(.*)$/.exec(line); + content = Base64.decode(base64Line); + + for (const addon of qs.split('&')) { + const [key, valueRaw] = addon.split('='); + let value = valueRaw; + value = decodeURIComponent(valueRaw); + if (value.indexOf(',') === -1) { + params[key] = value; + } else { + params[key] = value.split(','); + } + } + // eslint-disable-next-line no-unused-vars + let [___, cipher, uuid, server, port] = + /(^[^:]+?):([^:]+?)@(.*):(\d+)$/.exec(content); + + params.scy = cipher; + params.id = uuid; + params.port = port; + params.add = server; + } + const server = params.add; + const port = parseInt(getIfPresent(params.port), 10); + const proxy = { + name: + params.ps ?? + params.remarks ?? + params.remark ?? + `VMess ${server}:${port}`, + type: 'vmess', + server, + port, + cipher: getIfPresent(params.scy, 'auto'), + uuid: params.id, + alterId: parseInt( + getIfPresent(params.aid ?? params.alterId, 0), + 10, + ), + tls: ['tls', true, 1, '1'].includes(params.tls), + 'skip-cert-verify': isPresent(params.verify_cert) + ? !params.verify_cert + : undefined, + }; + if (!proxy['skip-cert-verify'] && isPresent(params.allowInsecure)) { + proxy['skip-cert-verify'] = /(TRUE)|1/i.test( + params.allowInsecure, + ); + } + // https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2) + if (proxy.tls) { + if (params.sni && params.sni !== '') { + proxy.sni = params.sni; + } else if (params.peer && params.peer !== '') { + proxy.sni = params.peer; + } + } + let httpupgrade = false; + // handle obfs + if (params.net === 'ws' || params.obfs === 'websocket') { + proxy.network = 'ws'; + } else if ( + ['http'].includes(params.net) || + ['http'].includes(params.obfs) || + ['http'].includes(params.type) + ) { + proxy.network = 'http'; + } else if (['grpc'].includes(params.net)) { + proxy.network = 'grpc'; + } else if ( + params.net === 'httpupgrade' || + proxy.network === 'httpupgrade' + ) { + proxy.network = 'ws'; + httpupgrade = true; + } else if (params.net === 'h2' || proxy.network === 'h2') { + proxy.network = 'h2'; + } + // 暂不支持 tcp + host + path + // else if (params.net === 'tcp' || proxy.network === 'tcp') { + // proxy.network = 'tcp'; + // } + if (proxy.network) { + let transportHost = params.host ?? params.obfsParam; + try { + const parsedObfs = JSON.parse(transportHost); + const parsedHost = parsedObfs?.Host; + if (parsedHost) { + transportHost = parsedHost; + } + // eslint-disable-next-line no-empty + } catch (e) {} + let transportPath = params.path; + + // 补上默认 path + if (['ws'].includes(proxy.network)) { + transportPath = transportPath || '/'; + } + + if (proxy.network === 'http') { + if (transportHost) { + // 1)http(tcp)->host中间逗号(,)隔开 + transportHost = transportHost + .split(',') + .map((i) => i.trim()); + transportHost = Array.isArray(transportHost) + ? transportHost[0] + : transportHost; + } + if (transportPath) { + transportPath = Array.isArray(transportPath) + ? transportPath[0] + : transportPath; + } else { + transportPath = '/'; + } + } + // 传输层应该有配置, 暂时不考虑兼容不给配置的节点 + if (transportPath || transportHost) { + if (['grpc'].includes(proxy.network)) { + proxy[`${proxy.network}-opts`] = { + 'grpc-service-name': getIfNotBlank(transportPath), + '_grpc-type': getIfNotBlank(params.type), + '_grpc-authority': getIfNotBlank(params.authority), + }; + } else { + const opts = { + path: getIfNotBlank(transportPath), + headers: { Host: getIfNotBlank(transportHost) }, + }; + if (httpupgrade) { + opts['v2ray-http-upgrade'] = true; + opts['v2ray-http-upgrade-fast-open'] = true; + } + proxy[`${proxy.network}-opts`] = opts; + } + } else { + delete proxy.network; + } + } + return proxy; + } + }; + return { name, test, parse }; +} + +function URI_VLESS() { + const name = 'URI VLESS Parser'; + const test = (line) => { + return /^vless:\/\//.test(line); + }; + const parse = (line) => { + line = line.split('vless://')[1]; + let isShadowrocket; + let parsed = /^(.*?)@(.*?):(\d+)\/?(\?(.*?))?(?:#(.*?))?$/.exec(line); + if (!parsed) { + // eslint-disable-next-line no-unused-vars + let [_, base64, other] = /^(.*?)(\?.*?$)/.exec(line); + line = `${Base64.decode(base64)}${other}`; + parsed = /^(.*?)@(.*?):(\d+)\/?(\?(.*?))?(?:#(.*?))?$/.exec(line); + isShadowrocket = true; + } + // eslint-disable-next-line no-unused-vars + let [__, uuid, server, port, ___, addons = '', name] = parsed; + if (isShadowrocket) { + uuid = uuid.replace(/^.*?:/g, ''); + } + + port = parseInt(`${port}`, 10); + uuid = decodeURIComponent(uuid); + if (name != null) { + name = decodeURIComponent(name); + } + + const proxy = { + type: 'vless', + name, + server, + port, + uuid, + }; + const params = {}; + for (const addon of addons.split('&')) { + const [key, valueRaw] = addon.split('='); + let value = valueRaw; + value = decodeURIComponent(valueRaw); + params[key] = value; + } + + proxy.name = + name ?? + params.remarks ?? + params.remark ?? + `VLESS ${server}:${port}`; + + proxy.tls = params.security && params.security !== 'none'; + if (isShadowrocket && /TRUE|1/i.test(params.tls)) { + proxy.tls = true; + params.security = params.security ?? 'reality'; + } + proxy.sni = params.sni || params.peer; + proxy.flow = params.flow; + if (!proxy.flow && isShadowrocket && params.xtls) { + // "none" is undefined + const flow = [undefined, 'xtls-rprx-direct', 'xtls-rprx-vision'][ + params.xtls + ]; + if (flow) { + proxy.flow = flow; + } + } + proxy['client-fingerprint'] = params.fp; + proxy.alpn = params.alpn ? params.alpn.split(',') : undefined; + proxy['skip-cert-verify'] = /(TRUE)|1/i.test(params.allowInsecure); + + if (['reality'].includes(params.security)) { + const opts = {}; + if (params.pbk) { + opts['public-key'] = params.pbk; + } + if (params.sid) { + opts['short-id'] = params.sid; + } + if (params.spx) { + opts['_spider-x'] = params.spx; + } + if (Object.keys(opts).length > 0) { + // proxy[`${params.security}-opts`] = opts; + proxy[`${params.security}-opts`] = opts; + } + } + let httpupgrade = false; + proxy.network = params.type; + if (proxy.network === 'tcp' && params.headerType === 'http') { + proxy.network = 'http'; + } else if (proxy.network === 'httpupgrade') { + proxy.network = 'ws'; + httpupgrade = true; + } + if (!proxy.network && isShadowrocket && params.obfs) { + proxy.network = params.obfs; + if (['none'].includes(proxy.network)) { + proxy.network = 'tcp'; + } + } + if (['websocket'].includes(proxy.network)) { + proxy.network = 'ws'; + } + if (proxy.network && !['tcp', 'none'].includes(proxy.network)) { + const opts = {}; + const host = params.host ?? params.obfsParam; + if (host) { + if (params.obfsParam) { + try { + const parsed = JSON.parse(host); + opts.headers = parsed; + } catch (e) { + opts.headers = { Host: host }; + } + } else { + opts.headers = { Host: host }; + } + } + if (params.serviceName) { + opts[`${proxy.network}-service-name`] = params.serviceName; + if (['grpc'].includes(proxy.network) && params.authority) { + opts['_grpc-authority'] = params.authority; + } + } else if (isShadowrocket && params.path) { + if (!['ws', 'http', 'h2'].includes(proxy.network)) { + opts[`${proxy.network}-service-name`] = params.path; + delete params.path; + } + } + if (params.path) { + opts.path = params.path; + } + // https://github.com/XTLS/Xray-core/issues/91 + if (['grpc'].includes(proxy.network)) { + opts['_grpc-type'] = params.mode || 'gun'; + } + if (httpupgrade) { + opts['v2ray-http-upgrade'] = true; + opts['v2ray-http-upgrade-fast-open'] = true; + } + if (Object.keys(opts).length > 0) { + proxy[`${proxy.network}-opts`] = opts; + } + if (proxy.network === 'kcp') { + // mKCP 种子。省略时不使用种子,但不可以为空字符串。建议 mKCP 用户使用 seed。 + if (params.seed) { + proxy.seed = params.seed; + } + // mKCP 的伪装头部类型。当前可选值有 none / srtp / utp / wechat-video / dtls / wireguard。省略时默认值为 none,即不使用伪装头部,但不可以为空字符串。 + proxy.headerType = params.headerType || 'none'; + } + + if (params.mode) { + proxy._mode = params.mode; + } + if (params.extra) { + proxy._extra = params.extra; + } + } + + return proxy; + }; + return { name, test, parse }; +} +function URI_AnyTLS() { + const name = 'URI AnyTLS Parser'; + const test = (line) => { + return /^anytls:\/\//.test(line); + }; + const parse = (line) => { + line = line.split(/anytls:\/\//)[1]; + // eslint-disable-next-line no-unused-vars + let [__, password, server, port, addons = '', name] = + /^(.*?)@(.*?)(?::(\d+))?\/?(?:\?(.*?))?(?:#(.*?))?$/.exec(line); + password = decodeURIComponent(password); + port = parseInt(`${port}`, 10); + if (isNaN(port)) { + port = 443; + } + password = decodeURIComponent(password); + if (name != null) { + name = decodeURIComponent(name); + } + name = name ?? `AnyTLS ${server}:${port}`; + + const proxy = { + type: 'anytls', + name, + server, + port, + password, + }; + + for (const addon of addons.split('&')) { + let [key, value] = addon.split('='); + key = key.replace(/_/g, '-'); + value = decodeURIComponent(value); + if (['alpn'].includes(key)) { + proxy[key] = value ? value.split(',') : undefined; + } else if (['insecure'].includes(key)) { + proxy['skip-cert-verify'] = /(TRUE)|1/i.test(value); + } else if (['udp'].includes(key)) { + proxy[key] = /(TRUE)|1/i.test(value); + } else { + proxy[key] = value; + } + } + + return proxy; + }; + return { name, test, parse }; +} +function URI_Hysteria2() { + const name = 'URI Hysteria2 Parser'; + const test = (line) => { + return /^(hysteria2|hy2):\/\//.test(line); + }; + const parse = (line) => { + line = line.split(/(hysteria2|hy2):\/\//)[2]; + // 端口跳跃有两种写法: + // 1. 服务器的地址和可选端口。如果省略端口,则默认为 443。 + // 端口部分支持 端口跳跃 的「多端口地址格式」。 + // https://hysteria.network/zh/docs/advanced/Port-Hopping + // 2. 参数 mport + let ports; + /* eslint-disable no-unused-vars */ + let [ + __, + password, + server, + ___, + port, + ____, + _____, + ______, + _______, + ________, + addons = '', + name, + ] = /^(.*?)@(.*?)(:((\d+(-\d+)?)([,;]\d+(-\d+)?)*))?\/?(\?(.*?))?(?:#(.*?))?$/.exec( + line, + ); + + /* eslint-enable no-unused-vars */ + if (/^\d+$/.test(port)) { + port = parseInt(`${port}`, 10); + if (isNaN(port)) { + port = 443; + } + } else if (port) { + ports = port; + port = getRandomPort(ports); + } else { + port = 443; + } + + password = decodeURIComponent(password); + if (name != null) { + name = decodeURIComponent(name); + } + name = name ?? `Hysteria2 ${server}:${port}`; + + const proxy = { + type: 'hysteria2', + name, + server, + port, + ports, + password, + }; + + const params = {}; + for (const addon of addons.split('&')) { + const [key, valueRaw] = addon.split('='); + let value = valueRaw; + value = decodeURIComponent(valueRaw); + params[key] = value; + } + + proxy.sni = params.sni; + if (!proxy.sni && params.peer) { + proxy.sni = params.peer; + } + if (params.obfs && params.obfs !== 'none') { + proxy.obfs = params.obfs; + } + if (params.mport) { + proxy.ports = params.mport; + } + proxy['obfs-password'] = params['obfs-password']; + proxy['skip-cert-verify'] = /(TRUE)|1/i.test(params.insecure); + proxy.tfo = /(TRUE)|1/i.test(params.fastopen); + proxy['tls-fingerprint'] = params.pinSHA256; + let hop_interval = params['hop-interval'] || params['hop_interval']; + + if (/^\d+$/.test(hop_interval)) { + proxy['hop-interval'] = parseInt(`${hop_interval}`, 10); + } + let keepalive = params['keepalive']; + + if (/^\d+$/.test(keepalive)) { + proxy['keepalive'] = parseInt(`${keepalive}`, 10); + } + + return proxy; + }; + return { name, test, parse }; +} +function URI_Hysteria() { + const name = 'URI Hysteria Parser'; + const test = (line) => { + return /^(hysteria|hy):\/\//.test(line); + }; + const parse = (line) => { + line = line.split(/(hysteria|hy):\/\//)[2]; + // eslint-disable-next-line no-unused-vars + let [__, server, ___, port, ____, addons = '', name] = + /^(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line); + port = parseInt(`${port}`, 10); + if (isNaN(port)) { + port = 443; + } + if (name != null) { + name = decodeURIComponent(name); + } + name = name ?? `Hysteria ${server}:${port}`; + + const proxy = { + type: 'hysteria', + name, + server, + port, + }; + const params = {}; + for (const addon of addons.split('&')) { + let [key, value] = addon.split('='); + key = key.replace(/_/, '-'); + value = decodeURIComponent(value); + if (['alpn'].includes(key)) { + proxy[key] = value ? value.split(',') : undefined; + } else if (['insecure'].includes(key)) { + proxy['skip-cert-verify'] = /(TRUE)|1/i.test(value); + } else if (['auth'].includes(key)) { + proxy['auth-str'] = value; + } else if (['mport'].includes(key)) { + proxy['ports'] = value; + } else if (['obfsParam'].includes(key)) { + proxy['obfs'] = value; + } else if (['upmbps'].includes(key)) { + proxy['up'] = value; + } else if (['downmbps'].includes(key)) { + proxy['down'] = value; + } else if (['obfs'].includes(key)) { + // obfs: Obfuscation mode (optional, empty or "xplus") + proxy['_obfs'] = value || ''; + } else if (['fast-open', 'peer'].includes(key)) { + params[key] = value; + } else { + proxy[key] = value; + } + } + + if (!proxy.sni && params.peer) { + proxy.sni = params.peer; + } + if (!proxy['fast-open'] && params.fastopen) { + proxy['fast-open'] = true; + } + if (!proxy.protocol) { + // protocol: protocol to use ("udp", "wechat-video", "faketcp") (optional, default: "udp") + proxy.protocol = 'udp'; + } + + return proxy; + }; + return { name, test, parse }; +} +function URI_TUIC() { + const name = 'URI TUIC Parser'; + const test = (line) => { + return /^tuic:\/\//.test(line); + }; + const parse = (line) => { + line = line.split(/tuic:\/\//)[1]; + // eslint-disable-next-line no-unused-vars + let [__, auth, server, port, addons = '', name] = + /^(.*?)@(.*?)(?::(\d+))?\/?(?:\?(.*?))?(?:#(.*?))?$/.exec(line); + auth = decodeURIComponent(auth); + let [uuid, ...passwordParts] = auth.split(':'); + let password = passwordParts.join(':'); + port = parseInt(`${port}`, 10); + if (isNaN(port)) { + port = 443; + } + password = decodeURIComponent(password); + if (name != null) { + name = decodeURIComponent(name); + } + name = name ?? `TUIC ${server}:${port}`; + + const proxy = { + type: 'tuic', + name, + server, + port, + password, + uuid, + }; + + for (const addon of addons.split('&')) { + let [key, value] = addon.split('='); + key = key.replace(/_/g, '-'); + value = decodeURIComponent(value); + if (['alpn'].includes(key)) { + proxy[key] = value ? value.split(',') : undefined; + } else if (['allow-insecure'].includes(key)) { + proxy['skip-cert-verify'] = /(TRUE)|1/i.test(value); + } else if (['fast-open'].includes(key)) { + proxy.tfo = true; + } else if (['disable-sni', 'reduce-rtt'].includes(key)) { + proxy[key] = /(TRUE)|1/i.test(value); + } else if (key === 'congestion-control') { + proxy['congestion-controller'] = value; + delete proxy[key]; + } else { + proxy[key] = value; + } + } + + return proxy; + }; + return { name, test, parse }; +} +function URI_WireGuard() { + const name = 'URI WireGuard Parser'; + const test = (line) => { + return /^(wireguard|wg):\/\//.test(line); + }; + const parse = (line) => { + line = line.split(/(wireguard|wg):\/\//)[2]; + /* eslint-disable no-unused-vars */ + let [ + __, + ___, + privateKey, + server, + ____, + port, + _____, + addons = '', + name, + ] = /^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line); + /* eslint-enable no-unused-vars */ + + port = parseInt(`${port}`, 10); + if (isNaN(port)) { + port = 51820; + } + privateKey = decodeURIComponent(privateKey); + if (name != null) { + name = decodeURIComponent(name); + } + name = name ?? `WireGuard ${server}:${port}`; + const proxy = { + type: 'wireguard', + name, + server, + port, + 'private-key': privateKey, + udp: true, + }; + for (const addon of addons.split('&')) { + let [key, value] = addon.split('='); + key = key.replace(/_/, '-'); + value = decodeURIComponent(value); + if (['reserved'].includes(key)) { + const parsed = value + .split(',') + .map((i) => parseInt(i.trim(), 10)) + .filter((i) => Number.isInteger(i)); + if (parsed.length === 3) { + proxy[key] = parsed; + } + } else if (['address', 'ip'].includes(key)) { + value.split(',').map((i) => { + const ip = i + .trim() + .replace(/\/\d+$/, '') + .replace(/^\[/, '') + .replace(/\]$/, ''); + if (isIPv4(ip)) { + proxy.ip = ip; + } else if (isIPv6(ip)) { + proxy.ipv6 = ip; + } + }); + } else if (['mtu'].includes(key)) { + const parsed = parseInt(value.trim(), 10); + if (Number.isInteger(parsed)) { + proxy[key] = parsed; + } + } else if (/publickey/i.test(key)) { + proxy['public-key'] = value; + } else if (/privatekey/i.test(key)) { + proxy['private-key'] = value; + } else if (['udp'].includes(key)) { + proxy[key] = /(TRUE)|1/i.test(value); + } else if (!['flag'].includes(key)) { + proxy[key] = value; + } + } + + return proxy; + }; + return { name, test, parse }; +} + +// Trojan URI format +function URI_Trojan() { + const name = 'URI Trojan Parser'; + const test = (line) => { + return /^trojan:\/\//.test(line); + }; + + const parse = (line) => { + const matched = /^(trojan:\/\/.*?@.*?)(:(\d+))?\/?(\?.*?)?$/.exec(line); + const port = matched?.[2]; + if (!port) { + line = line.replace(matched[1], `${matched[1]}:443`); + } + let [newLine, name] = line.split(/#(.+)/, 2); + const parser = getTrojanURIParser(); + const proxy = parser.parse(newLine); + if (isNotBlank(name)) { + try { + proxy.name = decodeURIComponent(name); + } catch (e) { + console.log(e); + } + } + return proxy; + }; + return { name, test, parse }; +} + +function Clash_All() { + const name = 'Clash Parser'; + const test = (line) => { + try { + JSON.parse(line); + } catch (e) { + return false; + } + return true; + }; + const parse = (line) => { + const proxy = JSON.parse(line); + if ( + ![ + 'anytls', + 'mieru', + 'juicity', + 'ss', + 'ssr', + 'vmess', + 'socks5', + 'http', + 'snell', + 'trojan', + 'tuic', + 'vless', + 'hysteria', + 'hysteria2', + 'wireguard', + 'ssh', + 'direct', + ].includes(proxy.type) + ) { + throw new Error( + `Clash does not support proxy with type: ${proxy.type}`, + ); + } + + // handle vmess sni + if (['vmess', 'vless'].includes(proxy.type)) { + proxy.sni = proxy.servername; + delete proxy.servername; + } + if (proxy['server-cert-fingerprint']) { + proxy['tls-fingerprint'] = proxy['server-cert-fingerprint']; + } + if (proxy.fingerprint) { + proxy['tls-fingerprint'] = proxy.fingerprint; + } + if (proxy['dialer-proxy']) { + proxy['underlying-proxy'] = proxy['dialer-proxy']; + } + + if (proxy['benchmark-url']) { + proxy['test-url'] = proxy['benchmark-url']; + } + if (proxy['benchmark-timeout']) { + proxy['test-timeout'] = proxy['benchmark-timeout']; + } + + return proxy; + }; + return { name, test, parse }; +} + +function QX_SS() { + const name = 'QX SS Parser'; + const test = (line) => { + return ( + /^shadowsocks\s*=/.test(line.split(',')[0].trim()) && + line.indexOf('ssr-protocol') === -1 + ); + }; + const parse = (line) => { + const parser = getQXParser(); + return parser.parse(line); + }; + return { name, test, parse }; +} + +function QX_SSR() { + const name = 'QX SSR Parser'; + const test = (line) => { + return ( + /^shadowsocks\s*=/.test(line.split(',')[0].trim()) && + line.indexOf('ssr-protocol') !== -1 + ); + }; + const parse = (line) => getQXParser().parse(line); + return { name, test, parse }; +} + +function QX_VMess() { + const name = 'QX VMess Parser'; + const test = (line) => { + return /^vmess\s*=/.test(line.split(',')[0].trim()); + }; + const parse = (line) => getQXParser().parse(line); + return { name, test, parse }; +} + +function QX_VLESS() { + const name = 'QX VLESS Parser'; + const test = (line) => { + return /^vless\s*=/.test(line.split(',')[0].trim()); + }; + const parse = (line) => getQXParser().parse(line); + return { name, test, parse }; +} + +function QX_Trojan() { + const name = 'QX Trojan Parser'; + const test = (line) => { + return /^trojan\s*=/.test(line.split(',')[0].trim()); + }; + const parse = (line) => getQXParser().parse(line); + return { name, test, parse }; +} + +function QX_Http() { + const name = 'QX HTTP Parser'; + const test = (line) => { + return /^http\s*=/.test(line.split(',')[0].trim()); + }; + const parse = (line) => getQXParser().parse(line); + return { name, test, parse }; +} + +function QX_Socks5() { + const name = 'QX Socks5 Parser'; + const test = (line) => { + return /^socks5\s*=/.test(line.split(',')[0].trim()); + }; + const parse = (line) => getQXParser().parse(line); + return { name, test, parse }; +} + +function Loon_SS() { + const name = 'Loon SS Parser'; + const test = (line) => { + return ( + line.split(',')[0].split('=')[1].trim().toLowerCase() === + 'shadowsocks' + ); + }; + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} + +function Loon_SSR() { + const name = 'Loon SSR Parser'; + const test = (line) => { + return ( + line.split(',')[0].split('=')[1].trim().toLowerCase() === + 'shadowsocksr' + ); + }; + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} + +function Loon_VMess() { + const name = 'Loon VMess Parser'; + const test = (line) => { + // distinguish between surge vmess + return ( + /^.*=\s*vmess/i.test(line.split(',')[0]) && + line.indexOf('username') === -1 + ); + }; + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} + +function Loon_Vless() { + const name = 'Loon Vless Parser'; + const test = (line) => { + return /^.*=\s*vless/i.test(line.split(',')[0]); + }; + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} + +function Loon_Trojan() { + const name = 'Loon Trojan Parser'; + const test = (line) => { + return /^.*=\s*trojan/i.test(line.split(',')[0]); + }; + + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} +function Loon_Hysteria2() { + const name = 'Loon Hysteria2 Parser'; + const test = (line) => { + return /^.*=\s*Hysteria2/i.test(line.split(',')[0]); + }; + + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} + +function Loon_Http() { + const name = 'Loon HTTP Parser'; + const test = (line) => { + return /^.*=\s*http/i.test(line.split(',')[0]); + }; + + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} +function Loon_Socks5() { + const name = 'Loon SOCKS5 Parser'; + const test = (line) => { + return /^.*=\s*socks5/i.test(line.split(',')[0]); + }; + + const parse = (line) => getLoonParser().parse(line); + return { name, test, parse }; +} + +function Loon_WireGuard() { + const name = 'Loon WireGuard Parser'; + const test = (line) => { + return /^.*=\s*wireguard/i.test(line.split(',')[0]); + }; + + const parse = (line) => { + const name = line.match( + /(^.*?)\s*?=\s*?wireguard\s*?,.+?\s*?=\s*?.+?/i, + )?.[1]; + line = line.replace(name, '').replace(/^\s*?=\s*?wireguard\s*/i, ''); + let peers = line.match( + /,\s*?peers\s*?=\s*?\[\s*?\{\s*?(.+?)\s*?\}\s*?\]/i, + )?.[1]; + let serverPort = peers.match( + /(,|^)\s*?endpoint\s*?=\s*?"?(.+?):(\d+)"?\s*?(,|$)/i, + ); + let server = serverPort?.[2]; + let port = parseInt(serverPort?.[3], 10); + let mtu = line.match(/(,|^)\s*?mtu\s*?=\s*?"?(\d+?)"?\s*?(,|$)/i)?.[2]; + if (mtu) { + mtu = parseInt(mtu, 10); + } + let keepalive = line.match( + /(,|^)\s*?keepalive\s*?=\s*?"?(\d+?)"?\s*?(,|$)/i, + )?.[2]; + if (keepalive) { + keepalive = parseInt(keepalive, 10); + } + let reserved = peers.match( + /(,|^)\s*?reserved\s*?=\s*?"?(\[\s*?.+?\s*?\])"?\s*?(,|$)/i, + )?.[2]; + if (reserved) { + reserved = JSON.parse(reserved); + } + + let dns; + let dnsv4 = line.match(/(,|^)\s*?dns\s*?=\s*?"?(.+?)"?\s*?(,|$)/i)?.[2]; + let dnsv6 = line.match( + /(,|^)\s*?dnsv6\s*?=\s*?"?(.+?)"?\s*?(,|$)/i, + )?.[2]; + if (dnsv4 || dnsv6) { + dns = []; + if (dnsv4) { + dns.push(dnsv4); + } + if (dnsv6) { + dns.push(dnsv6); + } + } + let allowedIps = peers + .match(/(,|^)\s*?allowed-ips\s*?=\s*?"(.+?)"\s*?(,|$)/i)?.[2] + ?.split(',') + .map((i) => i.trim()); + let preSharedKey = peers.match( + /(,|^)\s*?preshared-key\s*?=\s*?"?(.+?)"?\s*?(,|$)/i, + )?.[2]; + let ip = line.match( + /(,|^)\s*?interface-ip\s*?=\s*?"?(.+?)"?\s*?(,|$)/i, + )?.[2]; + let ipv6 = line.match( + /(,|^)\s*?interface-ipv6\s*?=\s*?"?(.+?)"?\s*?(,|$)/i, + )?.[2]; + let publicKey = peers.match( + /(,|^)\s*?public-key\s*?=\s*?"?(.+?)"?\s*?(,|$)/i, + )?.[2]; + // https://github.com/MetaCubeX/mihomo/blob/0404e35be8736b695eae018a08debb175c1f96e6/docs/config.yaml#L717 + const proxy = { + type: 'wireguard', + name, + server, + port, + ip, + ipv6, + 'private-key': line.match( + /(,|^)\s*?private-key\s*?=\s*?"?(.+?)"?\s*?(,|$)/i, + )?.[2], + 'public-key': publicKey, + mtu, + keepalive, + reserved, + 'allowed-ips': allowedIps, + 'preshared-key': preSharedKey, + dns, + udp: true, + peers: [ + { + server, + port, + ip, + ipv6, + 'public-key': publicKey, + 'pre-shared-key': preSharedKey, + 'allowed-ips': allowedIps, + reserved, + }, + ], + }; + + proxy; + if (Array.isArray(proxy.dns) && proxy.dns.length > 0) { + proxy['remote-dns-resolve'] = true; + } + return proxy; + }; + return { name, test, parse }; +} + +function Surge_Direct() { + const name = 'Surge Direct Parser'; + const test = (line) => { + return /^.*=\s*direct/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} +function Surge_SSH() { + const name = 'Surge SSH Parser'; + const test = (line) => { + return /^.*=\s*ssh/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} +function Surge_SS() { + const name = 'Surge SS Parser'; + const test = (line) => { + return /^.*=\s*ss/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} + +function Surge_VMess() { + const name = 'Surge VMess Parser'; + const test = (line) => { + return ( + /^.*=\s*vmess/.test(line.split(',')[0]) && + line.indexOf('username') !== -1 + ); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} + +function Surge_Trojan() { + const name = 'Surge Trojan Parser'; + const test = (line) => { + return /^.*=\s*trojan/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} + +function Surge_Http() { + const name = 'Surge HTTP Parser'; + const test = (line) => { + return /^.*=\s*https?/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} + +function Surge_Socks5() { + const name = 'Surge Socks5 Parser'; + const test = (line) => { + return /^.*=\s*socks5(-tls)?/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} + +function Surge_External() { + const name = 'Surge External Parser'; + const test = (line) => { + return /^.*=\s*external/.test(line.split(',')[0]); + }; + const parse = (line) => { + let parsed = /^\s*(.*?)\s*?=\s*?external\s*?,\s*(.*?)\s*$/.exec(line); + + // eslint-disable-next-line no-unused-vars + let [_, name, other] = parsed; + line = other; + + // exec = "/usr/bin/ssh" 或 exec = /usr/bin/ssh + let exec = /(,|^)\s*?exec\s*?=\s*"(.*?)"\s*?(,|$)/.exec(line)?.[2]; + if (!exec) { + exec = /(,|^)\s*?exec\s*?=\s*(.*?)\s*?(,|$)/.exec(line)?.[2]; + } + + // local-port = "1080" 或 local-port = 1080 + let localPort = /(,|^)\s*?local-port\s*?=\s*"(.*?)"\s*?(,|$)/.exec( + line, + )?.[2]; + if (!localPort) { + localPort = /(,|^)\s*?local-port\s*?=\s*(.*?)\s*?(,|$)/.exec( + line, + )?.[2]; + } + // args = "-m", args = "rc4-md5" + // args = -m, args = rc4-md5 + const argsRegex = /(,|^)\s*?args\s*?=\s*("(.*?)"|(.*?))(?=\s*?(,|$))/g; + let argsMatch; + const args = []; + while ((argsMatch = argsRegex.exec(line)) !== null) { + if (argsMatch[3] != null) { + args.push(argsMatch[3]); + } else if (argsMatch[4] != null) { + args.push(argsMatch[4]); + } + } + // addresses = "[ipv6]",,addresses = "ipv6", addresses = "ipv4" + // addresses = [ipv6], addresses = ipv6, addresses = ipv4 + const addressesRegex = + /(,|^)\s*?addresses\s*?=\s*("(.*?)"|(.*?))(?=\s*?(,|$))/g; + let addressesMatch; + const addresses = []; + while ((addressesMatch = addressesRegex.exec(line)) !== null) { + let ip; + if (addressesMatch[3] != null) { + ip = addressesMatch[3]; + } else if (addressesMatch[4] != null) { + ip = addressesMatch[4]; + } + if (ip != null) { + ip = `${ip}`.trim().replace(/^\[/, '').replace(/\]$/, ''); + } + if (isIP(ip)) { + addresses.push(ip); + } + } + + const proxy = { + type: 'external', + name, + exec, + 'local-port': localPort, + args, + addresses, + }; + return proxy; + }; + return { name, test, parse }; +} + +function Surge_Snell() { + const name = 'Surge Snell Parser'; + const test = (line) => { + return /^.*=\s*snell/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} + +function Surge_Tuic() { + const name = 'Surge Tuic Parser'; + const test = (line) => { + return /^.*=\s*tuic(-v5)?/.test(line.split(',')[0]); + }; + const parse = (raw) => { + const { port_hopping, line } = surge_port_hopping(raw); + const proxy = getSurgeParser().parse(line); + proxy['ports'] = port_hopping; + return proxy; + }; + return { name, test, parse }; +} +function Surge_WireGuard() { + const name = 'Surge WireGuard Parser'; + const test = (line) => { + return /^.*=\s*wireguard/.test(line.split(',')[0]); + }; + const parse = (line) => getSurgeParser().parse(line); + return { name, test, parse }; +} + +function Surge_Hysteria2() { + const name = 'Surge Hysteria2 Parser'; + const test = (line) => { + return /^.*=\s*hysteria2/.test(line.split(',')[0]); + }; + const parse = (raw) => { + const { port_hopping, line } = surge_port_hopping(raw); + const proxy = getSurgeParser().parse(line); + proxy['ports'] = port_hopping; + return proxy; + }; + return { name, test, parse }; +} + +function isIP(ip) { + return isIPv4(ip) || isIPv6(ip); +} + +export default [ + URI_PROXY(), + URI_SOCKS(), + URI_SS(), + URI_SSR(), + URI_VMess(), + URI_VLESS(), + URI_TUIC(), + URI_WireGuard(), + URI_Hysteria(), + URI_Hysteria2(), + URI_Trojan(), + URI_AnyTLS(), + Clash_All(), + Surge_Direct(), + Surge_SSH(), + Surge_SS(), + Surge_VMess(), + Surge_Trojan(), + Surge_Http(), + Surge_Snell(), + Surge_Tuic(), + Surge_WireGuard(), + Surge_Hysteria2(), + Surge_Socks5(), + Surge_External(), + Loon_SS(), + Loon_SSR(), + Loon_VMess(), + Loon_Vless(), + Loon_Hysteria2(), + Loon_Trojan(), + Loon_Http(), + Loon_Socks5(), + Loon_WireGuard(), + QX_SS(), + QX_SSR(), + QX_VMess(), + QX_VLESS(), + QX_Trojan(), + QX_Http(), + QX_Socks5(), +]; diff --git a/backend/src/core/proxy-utils/parsers/peggy/loon.js b/backend/src/core/proxy-utils/parsers/peggy/loon.js new file mode 100644 index 0000000000..5d5570fa17 --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/loon.js @@ -0,0 +1,210 @@ +import * as peggy from 'peggy'; +const grammars = String.raw` +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } +}} + +// per-parser initializer +{ + const proxy = {}; + const obfs = {}; + const transport = {}; + const $ = {}; + + function handleTransport() { + if (transport.type === "tcp") { /* do nothing */ } + else if (transport.type === "ws") { + proxy.network = "ws"; + $set(proxy, "ws-opts.path", transport.path); + $set(proxy, "ws-opts.headers.Host", transport.host); + } else if (transport.type === "http") { + proxy.network = "http"; + $set(proxy, "http-opts.path", transport.path); + $set(proxy, "http-opts.headers.Host", transport.host); + } + } +} + +start = (shadowsocksr/shadowsocks/vmess/vless/trojan/https/http/socks5/hysteria2) { + return proxy; +} + +shadowsocksr = tag equals "shadowsocksr"i address method password (ssr_protocol/ssr_protocol_param/obfs_ssr/obfs_ssr_param/obfs_host/obfs_uri/fast_open/udp_relay/udp_port/shadow_tls_version/shadow_tls_sni/shadow_tls_password/ip_mode/block_quic/others)*{ + proxy.type = "ssr"; + // handle ssr obfs + proxy.obfs = obfs.type; +} +shadowsocks = tag equals "shadowsocks"i address method password (obfs_typev obfs_hostv)? (obfs_ss/obfs_host/obfs_uri/fast_open/udp_relay/udp_port/shadow_tls_version/shadow_tls_sni/shadow_tls_password/ip_mode/block_quic/others)* { + proxy.type = "ss"; + // handle ss obfs + if (obfs.type == "http" || obfs.type === "tls") { + proxy.plugin = "obfs"; + $set(proxy, "plugin-opts.mode", obfs.type); + $set(proxy, "plugin-opts.host", obfs.host); + $set(proxy, "plugin-opts.path", obfs.path); + } +} +vmess = tag equals "vmess"i address method uuid (transport/transport_host/transport_path/over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/vmess_alterId/fast_open/udp_relay/ip_mode/public_key/short_id/block_quic/others)* { + proxy.type = "vmess"; + proxy.cipher = proxy.cipher || "none"; + proxy.alterId = proxy.alterId || 0; + handleTransport(); +} +vless = tag equals "vless"i address uuid (transport/transport_host/transport_path/over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/flow/public_key/short_id/block_quic/others)* { + proxy.type = "vless"; + handleTransport(); +} +trojan = tag equals "trojan"i address password (transport/transport_host/transport_path/over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "trojan"; + handleTransport(); +} +hysteria2 = tag equals "hysteria2"i address password (tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/udp_relay/fast_open/download_bandwidth/salamander_password/ecn/ip_mode/block_quic/others)* { + proxy.type = "hysteria2"; +} +https = tag equals "https"i address (username password)? (tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "http"; + proxy.tls = true; +} +http = tag equals "http"i address (username password)? (fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "http"; +} +socks5 = tag equals "socks5"i address (username password)? (over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "socks5"; +} + +address = comma server:server comma port:port { + proxy.server = server; + proxy.port = port; +} + +server = ip/domain + +ip = & { + const start = peg$currPos; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + j++; + } + peg$currPos = j; + $.ip = input.substring(start, j).trim(); + return true; +} { return $.ip; } + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } + throw new Error("Invalid domain: " + domain); +} + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } + throw new Error("Invalid port number: " + port); +} + +method = comma cipher:cipher { + proxy.cipher = cipher; +} +cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"auto"/"bf-cfb"/"camellia-128-cfb"/"camellia-192-cfb"/"camellia-256-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"none"/"rc4-md5"/"rc4"/"salsa20"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm"); + +username = & { + let j = peg$currPos; + let start, end; + let first = true; + while (j < input.length) { + if (input[j] === ',') { + if (first) { + start = j + 1; + first = false; + } else { + end = j; + break; + } + } + j++; + } + const match = input.substring(start, end); + if (match.indexOf("=") === -1) { + $.username = match; + peg$currPos = end; + return true; + } +} { proxy.username = $.username; } +password = comma '"' match:[^"]* '"' { proxy.password = match.join(""); } +uuid = comma '"' match:[^"]+ '"' { proxy.uuid = match.join(""); } + +obfs_typev = comma type:("http"/"tls") { obfs.type = type; } +obfs_hostv = comma match:[^,]+ { obfs.host = match.join(""); } + +obfs_ss = comma "obfs-name" equals type:("http"/"tls") { obfs.type = type; } + +obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { obfs.type = type; } +obfs_ssr_param = comma "obfs-param" equals match:$[^,]+ { proxy["obfs-param"] = match; } + +obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; } +obfs_uri = comma "obfs-uri" equals uri:uri { obfs.path = uri; } +uri = $[^,]+ + +transport = comma "transport" equals type:("tcp"/"ws"/"http") { transport.type = type; } +transport_host = comma "host" equals host:domain { transport.host = host; } +transport_path = comma "path" equals path:uri { transport.path = path; } + +ssr_protocol = comma "protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; } +ssr_protocol_param = comma "protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; } + +vmess_alterId = comma "alterId" equals alterId:$[0-9]+ { proxy.alterId = parseInt(alterId); } + +udp_port = comma "udp-port" equals match:$[0-9]+ { proxy["udp-port"] = parseInt(match.trim()); } +shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); } +shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); } +shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join(""); } + +over_tls = comma "over-tls" equals flag:bool { proxy.tls = flag; } +tls_host = comma sni:("tls-name"/"sni") equals host:domain { proxy.sni = host; } +tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; } +tls_cert_sha256 = comma "tls-cert-sha256" equals match:[^,]+ { proxy["tls-fingerprint"] = match.join("").replace(/^"(.*)"$/, '$1'); } +tls_pubkey_sha256 = comma "tls-pubkey-sha256" equals match:[^,]+ { proxy["tls-pubkey-sha256"] = match.join("").replace(/^"(.*)"$/, '$1'); } + +flow = comma "flow" equals match:[^,]+ { proxy["flow"] = match.join("").replace(/^"(.*)"$/, '$1'); } +public_key = comma "public-key" equals match:[^,]+ { proxy["reality-opts"] = proxy["reality-opts"] || {}; proxy["reality-opts"]["public-key"] = match.join("").replace(/^"(.*)"$/, '$1'); } +short_id = comma "short-id" equals match:[^,]+ { proxy["reality-opts"] = proxy["reality-opts"] || {}; proxy["reality-opts"]["short-id"] = match.join("").replace(/^"(.*)"$/, '$1'); } + +fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; } +udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; } +ip_mode = comma "ip-mode" equals match:[^,]+ { proxy["ip-version"] = match.join(""); } + +ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; } +download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); } +salamander_password = comma "salamander-password" equals match:[^,]+ { proxy['obfs-password'] = match.join(""); proxy.obfs = 'salamander'; } + +block_quic = comma "block-quic" equals flag:bool { if(flag) proxy["block-quic"] = "on"; else proxy["block-quic"] = "off"; } + +tag = match:[^=,]* { proxy.name = match.join("").trim(); } +comma = _ "," _ +equals = _ "=" _ +_ = [ \r\t]* +bool = b:("true"/"false") { return b === "true" } +others = comma [^=,]+ equals [^=,]+ +`; +let parser; +export default function getParser() { + if (!parser) { + parser = peggy.generate(grammars); + } + return parser; +} diff --git a/backend/src/core/proxy-utils/parsers/peggy/loon.peg b/backend/src/core/proxy-utils/parsers/peggy/loon.peg new file mode 100644 index 0000000000..77fe42f8ce --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/loon.peg @@ -0,0 +1,200 @@ +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } +}} + +// per-parser initializer +{ + const proxy = {}; + const obfs = {}; + const transport = {}; + const $ = {}; + + function handleTransport() { + if (transport.type === "tcp") { /* do nothing */ } + else if (transport.type === "ws") { + proxy.network = "ws"; + $set(proxy, "ws-opts.path", transport.path); + $set(proxy, "ws-opts.headers.Host", transport.host); + } else if (transport.type === "http") { + proxy.network = "http"; + $set(proxy, "http-opts.path", transport.path); + $set(proxy, "http-opts.headers.Host", transport.host); + } + } +} + +start = (shadowsocksr/shadowsocks/vmess/vless/trojan/https/http/socks5/hysteria2) { + return proxy; +} + +shadowsocksr = tag equals "shadowsocksr"i address method password (ssr_protocol/ssr_protocol_param/obfs_ssr/obfs_ssr_param/obfs_host/obfs_uri/fast_open/udp_relay/udp_port/shadow_tls_version/shadow_tls_sni/shadow_tls_password/ip_mode/block_quic/others)*{ + proxy.type = "ssr"; + // handle ssr obfs + proxy.obfs = obfs.type; +} +shadowsocks = tag equals "shadowsocks"i address method password (obfs_typev obfs_hostv)? (obfs_ss/obfs_host/obfs_uri/fast_open/udp_relay/udp_port/shadow_tls_version/shadow_tls_sni/shadow_tls_password/ip_mode/block_quic/others)* { + proxy.type = "ss"; + // handle ss obfs + if (obfs.type == "http" || obfs.type === "tls") { + proxy.plugin = "obfs"; + $set(proxy, "plugin-opts.mode", obfs.type); + $set(proxy, "plugin-opts.host", obfs.host); + $set(proxy, "plugin-opts.path", obfs.path); + } +} +vmess = tag equals "vmess"i address method uuid (transport/transport_host/transport_path/over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/vmess_alterId/fast_open/udp_relay/ip_mode/public_key/short_id/block_quic/others)* { + proxy.type = "vmess"; + proxy.cipher = proxy.cipher || "none"; + proxy.alterId = proxy.alterId || 0; + handleTransport(); +} +vless = tag equals "vless"i address uuid (transport/transport_host/transport_path/over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/flow/public_key/short_id/block_quic/others)* { + proxy.type = "vless"; + handleTransport(); +} +trojan = tag equals "trojan"i address password (transport/transport_host/transport_path/over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "trojan"; + handleTransport(); +} +hysteria2 = tag equals "hysteria2"i address password (tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/udp_relay/fast_open/download_bandwidth/salamander_password/ecn/ip_mode/block_quic/others)* { + proxy.type = "hysteria2"; +} +https = tag equals "https"i address (username password)? (tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "http"; + proxy.tls = true; +} +http = tag equals "http"i address (username password)? (fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "http"; +} +socks5 = tag equals "socks5"i address (username password)? (over_tls/tls_host/tls_verification/tls_cert_sha256/tls_pubkey_sha256/fast_open/udp_relay/ip_mode/block_quic/others)* { + proxy.type = "socks5"; +} + +address = comma server:server comma port:port { + proxy.server = server; + proxy.port = port; +} + +server = ip/domain + +ip = & { + const start = peg$currPos; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + j++; + } + peg$currPos = j; + $.ip = input.substring(start, j).trim(); + return true; +} { return $.ip; } + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } + throw new Error("Invalid domain: " + domain); +} + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } + throw new Error("Invalid port number: " + port); +} + +method = comma cipher:cipher { + proxy.cipher = cipher; +} +cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"auto"/"bf-cfb"/"camellia-128-cfb"/"camellia-192-cfb"/"camellia-256-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"none"/"rc4-md5"/"rc4"/"salsa20"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm"); + +username = & { + let j = peg$currPos; + let start, end; + let first = true; + while (j < input.length) { + if (input[j] === ',') { + if (first) { + start = j + 1; + first = false; + } else { + end = j; + break; + } + } + j++; + } + const match = input.substring(start, end); + if (match.indexOf("=") === -1) { + $.username = match; + peg$currPos = end; + return true; + } +} { proxy.username = $.username; } +password = comma '"' match:[^"]* '"' { proxy.password = match.join(""); } +uuid = comma '"' match:[^"]+ '"' { proxy.uuid = match.join(""); } + +obfs_typev = comma type:("http"/"tls") { obfs.type = type; } +obfs_hostv = comma match:[^,]+ { obfs.host = match.join(""); } + +obfs_ss = comma "obfs-name" equals type:("http"/"tls") { obfs.type = type; } + +obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { obfs.type = type; } +obfs_ssr_param = comma "obfs-param" equals match:$[^,]+ { proxy["obfs-param"] = match; } + +obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; } +obfs_uri = comma "obfs-uri" equals uri:uri { obfs.path = uri; } +uri = $[^,]+ + +transport = comma "transport" equals type:("tcp"/"ws"/"http") { transport.type = type; } +transport_host = comma "host" equals host:domain { transport.host = host; } +transport_path = comma "path" equals path:uri { transport.path = path; } + +ssr_protocol = comma "protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; } +ssr_protocol_param = comma "protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; } + +vmess_alterId = comma "alterId" equals alterId:$[0-9]+ { proxy.alterId = parseInt(alterId); } + +udp_port = comma "udp-port" equals match:$[0-9]+ { proxy["udp-port"] = parseInt(match.trim()); } +shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); } +shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); } +shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join(""); } + +over_tls = comma "over-tls" equals flag:bool { proxy.tls = flag; } +tls_host = comma sni:("tls-name"/"sni") equals host:domain { proxy.sni = host; } +tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; } +tls_cert_sha256 = comma "tls-cert-sha256" equals match:[^,]+ { proxy["tls-fingerprint"] = match.join("").replace(/^"(.*)"$/, '$1'); } +tls_pubkey_sha256 = comma "tls-pubkey-sha256" equals match:[^,]+ { proxy["tls-pubkey-sha256"] = match.join("").replace(/^"(.*)"$/, '$1'); } + +flow = comma "flow" equals match:[^,]+ { proxy["flow"] = match.join("").replace(/^"(.*)"$/, '$1'); } +public_key = comma "public-key" equals match:[^,]+ { proxy["reality-opts"] = proxy["reality-opts"] || {}; proxy["reality-opts"]["public-key"] = match.join("").replace(/^"(.*)"$/, '$1'); } +short_id = comma "short-id" equals match:[^,]+ { proxy["reality-opts"] = proxy["reality-opts"] || {}; proxy["reality-opts"]["short-id"] = match.join("").replace(/^"(.*)"$/, '$1'); } + +fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; } +udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; } +ip_mode = comma "ip-mode" equals match:[^,]+ { proxy["ip-version"] = match.join(""); } + +ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; } +download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); } +salamander_password = comma "salamander-password" equals match:[^,]+ { proxy['obfs-password'] = match.join(""); proxy.obfs = 'salamander'; } + +block_quic = comma "block-quic" equals flag:bool { if(flag) proxy["block-quic"] = "on"; else proxy["block-quic"] = "off"; } + +tag = match:[^=,]* { proxy.name = match.join("").trim(); } +comma = _ "," _ +equals = _ "=" _ +_ = [ \r\t]* +bool = b:("true"/"false") { return b === "true" } +others = comma [^=,]+ equals [^=,]+ \ No newline at end of file diff --git a/backend/src/core/proxy-utils/parsers/peggy/qx.js b/backend/src/core/proxy-utils/parsers/peggy/qx.js new file mode 100644 index 0000000000..2a0f229ee7 --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/qx.js @@ -0,0 +1,206 @@ +import * as peggy from 'peggy'; +const grammars = String.raw` +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } +}} + +// per-parse initializer +{ + const proxy = {}; + const obfs = {}; + const $ = {}; + + function handleObfs() { + if (obfs.type === "ws" || obfs.type === "wss") { + proxy.network = "ws"; + if (obfs.type === 'wss') { + proxy.tls = true; + } + $set(proxy, "ws-opts.path", obfs.path); + $set(proxy, "ws-opts.headers.Host", obfs.host); + } else if (obfs.type === "over-tls") { + proxy.tls = true; + } else if (obfs.type === "http") { + proxy.network = "http"; + $set(proxy, "http-opts.path", obfs.path); + $set(proxy, "http-opts.headers.Host", obfs.host); + } + } +} + +start = (trojan/shadowsocks/vmess/vless/http/socks5) { + return proxy +} + +trojan = "trojan" equals address + (password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/server_check_url/others)* { + proxy.type = "trojan"; + handleObfs(); +} + +shadowsocks = "shadowsocks" equals address + (password/method/obfs_ssr/obfs_ss/obfs_host/obfs_uri/ssr_protocol/ssr_protocol_param/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/udp_relay/udp_over_tcp_new/fast_open/tag/server_check_url/others)* { + if (proxy.protocol || proxy.type === "ssr") { + proxy.type = "ssr"; + if (!proxy.protocol) { + proxy.protocol = "origin"; + } + // handle ssr obfs + if (obfs.host) proxy["obfs-param"] = obfs.host; + if (obfs.type) proxy.obfs = obfs.type; + } else { + proxy.type = "ss"; + // handle ss obfs + if (obfs.type == "http" || obfs.type === "tls") { + proxy.plugin = "obfs"; + $set(proxy, "plugin-opts", { + mode: obfs.type + }); + } else if (obfs.type === "ws" || obfs.type === "wss") { + proxy.plugin = "v2ray-plugin"; + $set(proxy, "plugin-opts.mode", "websocket"); + if (obfs.type === "wss") { + $set(proxy, "plugin-opts.tls", true); + } + } else if (obfs.type === 'over-tls') { + throw new Error('ss over-tls is not supported'); + } + if (obfs.type) { + $set(proxy, "plugin-opts.host", obfs.host); + $set(proxy, "plugin-opts.path", obfs.path); + } + } +} + +vmess = "vmess" equals address + (uuid/method/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/server_check_url/others)* { + proxy.type = "vmess"; + proxy.cipher = proxy.cipher || "none"; + if (proxy.aead) { + proxy.alterId = 0; + } else { + proxy.alterId = proxy.alterId || 0; + } + handleObfs(); +} + +vless = "vless" equals address + (uuid/method/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/server_check_url/others)* { + proxy.type = "vless"; + proxy.cipher = proxy.cipher || "none"; + handleObfs(); +} + +http = "http" equals address + (username/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)*{ + proxy.type = "http"; +} + +socks5 = "socks5" equals address + (username/password/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)* { + proxy.type = "socks5"; +} + +address = server:server ":" port:port { + proxy.server = server; + proxy.port = port; +} +server = ip/domain + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } +} + +ip = & { + const start = peg$currPos; + let end; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + if (input[j] === ":") end = j; + j++; + } + peg$currPos = end || j; + $.ip = input.substring(start, end).trim(); + return true; +} { return $.ip; } + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } +} + +username = comma "username" equals username:[^,]+ { proxy.username = username.join("").trim(); } +password = comma "password" equals password:[^,]+ { proxy.password = password.join("").trim(); } +uuid = comma "password" equals uuid:[^,]+ { proxy.uuid = uuid.join("").trim(); } + +method = comma "method" equals cipher:cipher { + proxy.cipher = cipher; +}; +cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"bf-cfb"/"cast5-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"des-cfb"/"none"/"rc2-cfb"/"rc4-md5-6"/"rc4-md5"/"salsa20"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm"); +aead = comma "aead" equals flag:bool { proxy.aead = flag; } + +udp_relay = comma "udp-relay" equals flag:bool { proxy.udp = flag; } +udp_over_tcp = comma "udp-over-tcp" equals flag:bool { throw new Error("UDP over TCP is not supported"); } +udp_over_tcp_new = comma "udp-over-tcp" equals param:$[^=,]+ { if (param === "sp.v1") { proxy["udp-over-tcp"] = true; proxy["udp-over-tcp-version"] = 1; } else if (param === "sp.v2") { proxy["udp-over-tcp"] = true; proxy["udp-over-tcp-version"] = 2; } else if (param === "true") { proxy["_ssr_python_uot"] = true; } else { throw new Error("Invalid value for udp-over-tcp"); } } + +fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; } + +over_tls = comma "over-tls" equals flag:bool { proxy.tls = flag; } +tls_host = comma "tls-host" equals sni:domain { proxy.sni = sni; } +tls_verification = comma "tls-verification" equals flag:bool { + proxy["skip-cert-verify"] = !flag; +} +tls_fingerprint = comma "tls-cert-sha256" equals tls_fingerprint:$[^,]+ { proxy["tls-fingerprint"] = tls_fingerprint.trim(); } +tls_pubkey_sha256 = comma "tls-pubkey-sha256" equals param:$[^=,]+ { proxy["tls-pubkey-sha256"] = param; } +tls_alpn = comma "tls-alpn" equals param:$[^=,]+ { proxy["tls-alpn"] = param; } +tls_no_session_ticket = comma "tls-no-session-ticket" equals flag:bool { + proxy["tls-no-session-ticket"] = flag; +} +tls_no_session_reuse = comma "tls-no-session-reuse" equals flag:bool { + proxy["tls-no-session-reuse"] = flag; +} + +obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws"/"over-tls") { obfs.type = type; return type; } +obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { proxy.type = "ssr"; obfs.type = type; return type; } +obfs = comma "obfs" equals type:("wss"/"ws"/"over-tls"/"http") { obfs.type = type; return type; }; + +obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; } +obfs_uri = comma "obfs-uri" equals uri:uri { obfs.path = uri; } + +ssr_protocol = comma "ssr-protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; return protocol; } +ssr_protocol_param = comma "ssr-protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; } + +server_check_url = comma "server_check_url" equals param:$[^=,]+ { proxy["test-url"] = param; } + +uri = $[^,]+ + +tag = comma "tag" equals tag:[^=,]+ { proxy.name = tag.join(""); } +others = comma [^=,]+ equals [^=,]+ +comma = _ "," _ +equals = _ "=" _ +_ = [ \r\t]* +bool = b:("true"/"false") { return b === "true" } +`; +let parser; +export default function getParser() { + if (!parser) { + parser = peggy.generate(grammars); + } + return parser; +} diff --git a/backend/src/core/proxy-utils/parsers/peggy/qx.peg b/backend/src/core/proxy-utils/parsers/peggy/qx.peg new file mode 100644 index 0000000000..00a84cd094 --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/qx.peg @@ -0,0 +1,196 @@ +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } +}} + +// per-parse initializer +{ + const proxy = {}; + const obfs = {}; + const $ = {}; + + function handleObfs() { + if (obfs.type === "ws" || obfs.type === "wss") { + proxy.network = "ws"; + if (obfs.type === 'wss') { + proxy.tls = true; + } + $set(proxy, "ws-opts.path", obfs.path); + $set(proxy, "ws-opts.headers.Host", obfs.host); + } else if (obfs.type === "over-tls") { + proxy.tls = true; + } else if (obfs.type === "http") { + proxy.network = "http"; + $set(proxy, "http-opts.path", obfs.path); + $set(proxy, "http-opts.headers.Host", obfs.host); + } + } +} + +start = (trojan/shadowsocks/vmess/vless/http/socks5) { + return proxy +} + +trojan = "trojan" equals address + (password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/server_check_url/others)* { + proxy.type = "trojan"; + handleObfs(); +} + +shadowsocks = "shadowsocks" equals address + (password/method/obfs_ssr/obfs_ss/obfs_host/obfs_uri/ssr_protocol/ssr_protocol_param/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/udp_relay/udp_over_tcp_new/fast_open/tag/server_check_url/others)* { + if (proxy.protocol || proxy.type === "ssr") { + proxy.type = "ssr"; + if (!proxy.protocol) { + proxy.protocol = "origin"; + } + // handle ssr obfs + if (obfs.host) proxy["obfs-param"] = obfs.host; + if (obfs.type) proxy.obfs = obfs.type; + } else { + proxy.type = "ss"; + // handle ss obfs + if (obfs.type == "http" || obfs.type === "tls") { + proxy.plugin = "obfs"; + $set(proxy, "plugin-opts", { + mode: obfs.type + }); + } else if (obfs.type === "ws" || obfs.type === "wss") { + proxy.plugin = "v2ray-plugin"; + $set(proxy, "plugin-opts.mode", "websocket"); + if (obfs.type === "wss") { + $set(proxy, "plugin-opts.tls", true); + } + } else if (obfs.type === 'over-tls') { + throw new Error('ss over-tls is not supported'); + } + if (obfs.type) { + $set(proxy, "plugin-opts.host", obfs.host); + $set(proxy, "plugin-opts.path", obfs.path); + } + } +} + +vmess = "vmess" equals address + (uuid/method/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/server_check_url/others)* { + proxy.type = "vmess"; + proxy.cipher = proxy.cipher || "none"; + if (proxy.aead) { + proxy.alterId = 0; + } else { + proxy.alterId = proxy.alterId || 0; + } + handleObfs(); +} + +vless = "vless" equals address + (uuid/method/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/server_check_url/others)* { + proxy.type = "vless"; + proxy.cipher = proxy.cipher || "none"; + handleObfs(); +} + +http = "http" equals address + (username/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)*{ + proxy.type = "http"; +} + +socks5 = "socks5" equals address + (username/password/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)* { + proxy.type = "socks5"; +} + +address = server:server ":" port:port { + proxy.server = server; + proxy.port = port; +} +server = ip/domain + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } +} + +ip = & { + const start = peg$currPos; + let end; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + if (input[j] === ":") end = j; + j++; + } + peg$currPos = end || j; + $.ip = input.substring(start, end).trim(); + return true; +} { return $.ip; } + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } +} + +username = comma "username" equals username:[^,]+ { proxy.username = username.join("").trim(); } +password = comma "password" equals password:[^,]+ { proxy.password = password.join("").trim(); } +uuid = comma "password" equals uuid:[^,]+ { proxy.uuid = uuid.join("").trim(); } + +method = comma "method" equals cipher:cipher { + proxy.cipher = cipher; +}; +cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"bf-cfb"/"cast5-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"des-cfb"/"none"/"rc2-cfb"/"rc4-md5-6"/"rc4-md5"/"salsa20"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm"); +aead = comma "aead" equals flag:bool { proxy.aead = flag; } + +udp_relay = comma "udp-relay" equals flag:bool { proxy.udp = flag; } +udp_over_tcp = comma "udp-over-tcp" equals flag:bool { throw new Error("UDP over TCP is not supported"); } +udp_over_tcp_new = comma "udp-over-tcp" equals param:$[^=,]+ { if (param === "sp.v1") { proxy["udp-over-tcp"] = true; proxy["udp-over-tcp-version"] = 1; } else if (param === "sp.v2") { proxy["udp-over-tcp"] = true; proxy["udp-over-tcp-version"] = 2; } else if (param === "true") { proxy["_ssr_python_uot"] = true; } else { throw new Error("Invalid value for udp-over-tcp"); } } + +fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; } + +over_tls = comma "over-tls" equals flag:bool { proxy.tls = flag; } +tls_host = comma "tls-host" equals sni:domain { proxy.sni = sni; } +tls_verification = comma "tls-verification" equals flag:bool { + proxy["skip-cert-verify"] = !flag; +} +tls_fingerprint = comma "tls-cert-sha256" equals tls_fingerprint:$[^,]+ { proxy["tls-fingerprint"] = tls_fingerprint.trim(); } +tls_pubkey_sha256 = comma "tls-pubkey-sha256" equals param:$[^=,]+ { proxy["tls-pubkey-sha256"] = param; } +tls_alpn = comma "tls-alpn" equals param:$[^=,]+ { proxy["tls-alpn"] = param; } +tls_no_session_ticket = comma "tls-no-session-ticket" equals flag:bool { + proxy["tls-no-session-ticket"] = flag; +} +tls_no_session_reuse = comma "tls-no-session-reuse" equals flag:bool { + proxy["tls-no-session-reuse"] = flag; +} + +obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws"/"over-tls") { obfs.type = type; return type; } +obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { proxy.type = "ssr"; obfs.type = type; return type; } +obfs = comma "obfs" equals type:("wss"/"ws"/"over-tls"/"http") { obfs.type = type; return type; }; + +obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; } +obfs_uri = comma "obfs-uri" equals uri:uri { obfs.path = uri; } + +ssr_protocol = comma "ssr-protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; return protocol; } +ssr_protocol_param = comma "ssr-protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; } + +server_check_url = comma "server_check_url" equals param:$[^=,]+ { proxy["test-url"] = param; } + +uri = $[^,]+ + +tag = comma "tag" equals tag:[^=,]+ { proxy.name = tag.join(""); } +others = comma [^=,]+ equals [^=,]+ +comma = _ "," _ +equals = _ "=" _ +_ = [ \r\t]* +bool = b:("true"/"false") { return b === "true" } \ No newline at end of file diff --git a/backend/src/core/proxy-utils/parsers/peggy/surge.js b/backend/src/core/proxy-utils/parsers/peggy/surge.js new file mode 100644 index 0000000000..eb0aec3210 --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/surge.js @@ -0,0 +1,267 @@ +import * as peggy from 'peggy'; +const grammars = String.raw` +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } +}} + +// per-parser initializer +{ + const proxy = {}; + const obfs = {}; + const $ = {}; + + function handleWebsocket() { + if (obfs.type === "ws") { + proxy.network = "ws"; + $set(proxy, "ws-opts.path", obfs.path); + $set(proxy, "ws-opts.headers", obfs['ws-headers']); + if (proxy['ws-opts'] && proxy['ws-opts']['headers'] && proxy['ws-opts']['headers'].Host) { + proxy['ws-opts']['headers'].Host = proxy['ws-opts']['headers'].Host.replace(/^"(.*)"$/, '$1') + } + } + } + function handleShadowTLS() { + if (proxy['shadow-tls-password'] && !proxy['shadow-tls-version']) { + proxy['shadow-tls-version'] = 2; + } + } +} + +start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2/ssh/direct) { + return proxy; +} + +shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/udp_port/others)* { + proxy.type = "ss"; + // handle obfs + if (obfs.type == "http" || obfs.type === "tls") { + proxy.plugin = "obfs"; + $set(proxy, "plugin-opts.mode", obfs.type); + $set(proxy, "plugin-opts.host", obfs.host); + $set(proxy, "plugin-opts.path", obfs.path); + } + handleShadowTLS(); +} +vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls/sni/tls_fingerprint/tls_verification/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "vmess"; + proxy.cipher = proxy.cipher || "none"; + if (proxy.aead) { + proxy.alterId = 0; + } else { + proxy.alterId = proxy.alterId || 0; + } + handleWebsocket(); + handleShadowTLS(); +} +trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "trojan"; + handleWebsocket(); + handleShadowTLS(); +} +https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "http"; + proxy.tls = true; + handleShadowTLS(); +} +http = tag equals "http" address (username password)? (usernamek passwordk)? (ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "http"; + handleShadowTLS(); +} +ssh = tag equals "ssh" address (username password)? (usernamek passwordk)? (server_fingerprint/idle_timeout/private_key/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "ssh"; + handleShadowTLS(); +} +snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "snell"; + // handle obfs + if (obfs.type == "http" || obfs.type === "tls") { + $set(proxy, "obfs-opts.mode", obfs.type); + $set(proxy, "obfs-opts.host", obfs.host); + $set(proxy, "obfs-opts.path", obfs.path); + } + handleShadowTLS(); +} +tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* { + proxy.type = "tuic"; + handleShadowTLS(); +} +tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* { + proxy.type = "tuic"; + proxy.version = 5; + handleShadowTLS(); +} +wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "wireguard-surge"; + handleShadowTLS(); +} +hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/fast_open/tfo/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* { + proxy.type = "hysteria2"; + handleShadowTLS(); +} +socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (udp_relay/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "socks5"; + handleShadowTLS(); +} +socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (udp_relay/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_fingerprint/tls_verification/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "socks5"; + proxy.tls = true; + handleShadowTLS(); +} +direct = tag equals "direct" (udp_relay/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/block_quic/others)* { + proxy.type = "direct"; +} + +address = comma server:server comma port:port { + proxy.server = server; + proxy.port = port; +} + +server = ip/domain + +ip = & { + const start = peg$currPos; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + j++; + } + peg$currPos = j; + $.ip = input.substring(start, j).trim(); + return true; +} { return $.ip; } + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } +} + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } +} + +port_hopping_interval = comma "port-hopping-interval" equals match:$[0-9]+ { proxy["hop-interval"] = parseInt(match.trim()); } + +username = & { + let j = peg$currPos; + let start, end; + let first = true; + while (j < input.length) { + if (input[j] === ',') { + if (first) { + start = j + 1; + first = false; + } else { + end = j; + break; + } + } + j++; + } + const match = input.substring(start, end); + if (match.indexOf("=") === -1) { + $.username = match; + peg$currPos = end; + return true; + } +} { proxy.username = $.username; } +password = comma match:[^,]+ { proxy.password = match.join(""); } + +tls = comma "tls" equals flag:bool { proxy.tls = flag; } +sni = comma "sni" equals sni:("off"/domain) { + if (sni === "off") { + proxy["disable-sni"] = true; + } else { + proxy.sni = sni; + } +} +tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; } +tls_fingerprint = comma "server-cert-fingerprint-sha256" equals tls_fingerprint:$[^,]+ { proxy["tls-fingerprint"] = tls_fingerprint.trim(); } + +snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); } +snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); } + +usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join(""); } +passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); } +vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); } +vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; } + +method = comma "encrypt-method" equals cipher:cipher { + proxy.cipher = cipher; +} +cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"bf-cfb"/"camellia-128-cfb"/"camellia-192-cfb"/"camellia-256-cfb"/"cast5-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"des-cfb"/"idea-cfb"/"none"/"rc2-cfb"/"rc4-md5"/"rc4"/"salsa20"/"seed-cfb"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm"); + +ws = comma "ws" equals flag:bool { obfs.type = "ws"; } +ws_headers = comma "ws-headers" equals headers:$[^,]+ { + const pairs = headers.split("|"); + const result = {}; + pairs.forEach(pair => { + const [key, value] = pair.trim().split(":"); + result[key.trim()] = value.trim(); + }) + obfs["ws-headers"] = result; +} +ws_path = comma "ws-path" equals path:uri { obfs.path = path; } + +obfs = comma "obfs" equals type:("http"/"tls") { obfs.type = type; } +obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; }; +obfs_uri = comma "obfs-uri" equals path:uri { obfs.path = path } +uri = $[^,]+ + +udp_relay = comma "udp-relay" equals flag:bool { proxy.udp = flag; } +fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; } +reuse = comma "reuse" equals flag:bool { proxy.reuse = flag; } +ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; } +tfo = comma "tfo" equals flag:bool { proxy.tfo = flag; } +ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); } +section_name = comma "section-name" equals match:[^,]+ { proxy["section-name"] = match.join(""); } +no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-alert"] = match.join(""); } +underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); } +download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); } +test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); } +test_udp = comma "test-udp" equals match:[^,]+ { proxy["test-udp"] = match.join(""); } +test_timeout = comma "test-timeout" equals match:$[0-9]+ { proxy["test-timeout"] = parseInt(match.trim()); } +tos = comma "tos" equals match:$[0-9]+ { proxy.tos = parseInt(match.trim()); } +interface = comma "interface" equals match:[^,]+ { proxy.interface = match.join(""); } +allow_other_interface = comma "allow-other-interface" equals flag:bool { proxy["allow-other-interface"] = flag; } +hybrid = comma "hybrid" equals flag:bool { proxy.hybrid = flag; } +idle_timeout = comma "idle-timeout" equals match:$[0-9]+ { proxy["idle-timeout"] = parseInt(match.trim()); } +private_key = comma "private-key" equals match:[^,]+ { proxy["keystore-private-key"] = match.join("").replace(/^"(.*)"$/, '$1'); } +server_fingerprint = comma "server-fingerprint" equals match:[^,]+ { proxy["server-fingerprint"] = match.join("").replace(/^"(.*)"$/, '$1'); } +block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); } +udp_port = comma "udp-port" equals match:$[0-9]+ { proxy["udp-port"] = parseInt(match.trim()); } +shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); } +shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); } +shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); } +token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); } +alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); } +uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); } + +tag = match:[^=,]* { proxy.name = match.join("").trim(); } +comma = _ "," _ +equals = _ "=" _ +_ = [ \r\t]* +bool = b:("true"/"false") { return b === "true" } +others = comma [^=,]+ equals [^=,]+ +`; +let parser; +export default function getParser() { + if (!parser) { + parser = peggy.generate(grammars); + } + return parser; +} diff --git a/backend/src/core/proxy-utils/parsers/peggy/surge.peg b/backend/src/core/proxy-utils/parsers/peggy/surge.peg new file mode 100644 index 0000000000..5128a7d638 --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/surge.peg @@ -0,0 +1,256 @@ +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } +}} + +// per-parser initializer +{ + const proxy = {}; + const obfs = {}; + const $ = {}; + + function handleWebsocket() { + if (obfs.type === "ws") { + proxy.network = "ws"; + $set(proxy, "ws-opts.path", obfs.path); + $set(proxy, "ws-opts.headers", obfs['ws-headers']); + if (proxy['ws-opts'] && proxy['ws-opts']['headers'] && proxy['ws-opts']['headers'].Host) { + proxy['ws-opts']['headers'].Host = proxy['ws-opts']['headers'].Host.replace(/^"(.*)"$/, '$1') + } + } + } + function handleShadowTLS() { + if (proxy['shadow-tls-password'] && !proxy['shadow-tls-version']) { + proxy['shadow-tls-version'] = 2; + } + } +} + +start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2/ssh/direct) { + return proxy; +} + +shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/udp_port/others)* { + proxy.type = "ss"; + // handle obfs + if (obfs.type == "http" || obfs.type === "tls") { + proxy.plugin = "obfs"; + $set(proxy, "plugin-opts.mode", obfs.type); + $set(proxy, "plugin-opts.host", obfs.host); + $set(proxy, "plugin-opts.path", obfs.path); + } + handleShadowTLS(); +} +vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls/sni/tls_fingerprint/tls_verification/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "vmess"; + proxy.cipher = proxy.cipher || "none"; + if (proxy.aead) { + proxy.alterId = 0; + } else { + proxy.alterId = proxy.alterId || 0; + } + handleWebsocket(); + handleShadowTLS(); +} +trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "trojan"; + handleWebsocket(); + handleShadowTLS(); +} +https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "http"; + proxy.tls = true; + handleShadowTLS(); +} +http = tag equals "http" address (username password)? (usernamek passwordk)? (ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "http"; + handleShadowTLS(); +} +ssh = tag equals "ssh" address (username password)? (usernamek passwordk)? (server_fingerprint/idle_timeout/private_key/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "ssh"; + handleShadowTLS(); +} +snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "snell"; + // handle obfs + if (obfs.type == "http" || obfs.type === "tls") { + $set(proxy, "obfs-opts.mode", obfs.type); + $set(proxy, "obfs-opts.host", obfs.host); + $set(proxy, "obfs-opts.path", obfs.path); + } + handleShadowTLS(); +} +tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* { + proxy.type = "tuic"; + handleShadowTLS(); +} +tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* { + proxy.type = "tuic"; + proxy.version = 5; + handleShadowTLS(); +} +wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "wireguard-surge"; + handleShadowTLS(); +} +hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* { + proxy.type = "hysteria2"; + handleShadowTLS(); +} +socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (udp_relay/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "socks5"; + handleShadowTLS(); +} +socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (udp_relay/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_fingerprint/tls_verification/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* { + proxy.type = "socks5"; + proxy.tls = true; + handleShadowTLS(); +} +direct = tag equals "direct" (udp_relay/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/block_quic/others)* { + proxy.type = "direct"; +} +address = comma server:server comma port:port { + proxy.server = server; + proxy.port = port; +} + +server = ip/domain + +ip = & { + const start = peg$currPos; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + j++; + } + peg$currPos = j; + $.ip = input.substring(start, j).trim(); + return true; +} { return $.ip; } + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } +} + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } +} + +port_hopping_interval = comma "port-hopping-interval" equals match:$[0-9]+ { proxy["hop-interval"] = parseInt(match.trim()); } + +username = & { + let j = peg$currPos; + let start, end; + let first = true; + while (j < input.length) { + if (input[j] === ',') { + if (first) { + start = j + 1; + first = false; + } else { + end = j; + break; + } + } + j++; + } + const match = input.substring(start, end); + if (match.indexOf("=") === -1) { + $.username = match; + peg$currPos = end; + return true; + } +} { proxy.username = $.username; } +password = comma match:[^,]+ { proxy.password = match.join(""); } + +tls = comma "tls" equals flag:bool { proxy.tls = flag; } +sni = comma "sni" equals sni:("off"/domain) { + if (sni === "off") { + proxy["disable-sni"] = true; + } else { + proxy.sni = sni; + } +} +tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; } +tls_fingerprint = comma "server-cert-fingerprint-sha256" equals tls_fingerprint:$[^,]+ { proxy["tls-fingerprint"] = tls_fingerprint.trim(); } + +snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); } +snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); } + +usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join(""); } +passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); } +vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); } +vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; } + +method = comma "encrypt-method" equals cipher:cipher { + proxy.cipher = cipher; +} +cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"bf-cfb"/"camellia-128-cfb"/"camellia-192-cfb"/"camellia-256-cfb"/"cast5-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"des-cfb"/"idea-cfb"/"none"/"rc2-cfb"/"rc4-md5"/"rc4"/"salsa20"/"seed-cfb"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm"); + +ws = comma "ws" equals flag:bool { obfs.type = "ws"; } +ws_headers = comma "ws-headers" equals headers:$[^,]+ { + const pairs = headers.split("|"); + const result = {}; + pairs.forEach(pair => { + const [key, value] = pair.trim().split(":"); + result[key.trim()] = value.trim(); + }) + obfs["ws-headers"] = result; +} +ws_path = comma "ws-path" equals path:uri { obfs.path = path; } + +obfs = comma "obfs" equals type:("http"/"tls") { obfs.type = type; } +obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; }; +obfs_uri = comma "obfs-uri" equals path:uri { obfs.path = path } +uri = $[^,]+ + +udp_relay = comma "udp-relay" equals flag:bool { proxy.udp = flag; } +fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; } +reuse = comma "reuse" equals flag:bool { proxy.reuse = flag; } +ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; } +tfo = comma "tfo" equals flag:bool { proxy.tfo = flag; } +ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); } +section_name = comma "section-name" equals match:[^,]+ { proxy["section-name"] = match.join(""); } +no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-alert"] = match.join(""); } +underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); } +download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); } +test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); } +test_udp = comma "test-udp" equals match:[^,]+ { proxy["test-udp"] = match.join(""); } +test_timeout = comma "test-timeout" equals match:$[0-9]+ { proxy["test-timeout"] = parseInt(match.trim()); } +tos = comma "tos" equals match:$[0-9]+ { proxy.tos = parseInt(match.trim()); } +interface = comma "interface" equals match:[^,]+ { proxy.interface = match.join(""); } +allow_other_interface = comma "allow-other-interface" equals flag:bool { proxy["allow-other-interface"] = flag; } +hybrid = comma "hybrid" equals flag:bool { proxy.hybrid = flag; } +idle_timeout = comma "idle-timeout" equals match:$[0-9]+ { proxy["idle-timeout"] = parseInt(match.trim()); } +private_key = comma "private-key" equals match:[^,]+ { proxy["keystore-private-key"] = match.join("").replace(/^"(.*)"$/, '$1'); } +server_fingerprint = comma "server-fingerprint" equals match:[^,]+ { proxy["server-fingerprint"] = match.join("").replace(/^"(.*)"$/, '$1'); } +block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); } +udp_port = comma "udp-port" equals match:$[0-9]+ { proxy["udp-port"] = parseInt(match.trim()); } +shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); } +shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); } +shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); } +token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); } +alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); } +uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); } + +tag = match:[^=,]* { proxy.name = match.join("").trim(); } +comma = _ "," _ +equals = _ "=" _ +_ = [ \r\t]* +bool = b:("true"/"false") { return b === "true" } +others = comma [^=,]+ equals [^=,]+ \ No newline at end of file diff --git a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js new file mode 100644 index 0000000000..bc27623d31 --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js @@ -0,0 +1,168 @@ +import * as peggy from 'peggy'; +const grammars = String.raw` +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } + + function toBool(str) { + if (typeof str === 'undefined' || str === null) return undefined; + return /(TRUE)|1/i.test(str); + } +}} + +{ + const proxy = {}; + const obfs = {}; + const $ = {}; + const params = {}; +} + +start = (trojan) { + return proxy +} + +trojan = "trojan://" password:password "@" server:server ":" port:port "/"? params? name:name?{ + proxy.type = "trojan"; + proxy.password = password; + proxy.server = server; + proxy.port = port; + proxy.name = name; + + // name may be empty + if (!proxy.name) { + proxy.name = server + ":" + port; + } +}; + +password = match:$[^@]+ { + return decodeURIComponent(match); +}; + +server = ip/domain; + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } +} + +ip = & { + const start = peg$currPos; + let end; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + if (input[j] === ":") end = j; + j++; + } + peg$currPos = end || j; + $.ip = input.substring(start, end).trim(); + return true; +} { return $.ip; } + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } else { + throw new Error("Invalid port: " + port); + } +} + +params = "?" head:param tail:("&"@param)* { + for (const [key, value] of Object.entries(params)) { + params[key] = decodeURIComponent(value); + } + proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); + proxy.sni = params["sni"] || params["peer"]; + proxy['client-fingerprint'] = params.fp; + proxy.alpn = params.alpn ? decodeURIComponent(params.alpn).split(',') : undefined; + + if (toBool(params["ws"])) { + proxy.network = "ws"; + $set(proxy, "ws-opts.path", params["wspath"]); + } + + if (params["type"]) { + let httpupgrade + proxy.network = params["type"] + if(proxy.network === 'httpupgrade') { + proxy.network = 'ws' + httpupgrade = true + } + if (['grpc'].includes(proxy.network)) { + proxy[proxy.network + '-opts'] = { + 'grpc-service-name': params["serviceName"], + '_grpc-type': params["mode"], + '_grpc-authority': params["authority"], + }; + } else { + if (params["path"]) { + $set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"])); + } + if (params["host"]) { + $set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"])); + } + if (httpupgrade) { + $set(proxy, proxy.network+"-opts.v2ray-http-upgrade", true); + $set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true); + } + } + if (['reality'].includes(params.security)) { + const opts = {}; + if (params.pbk) { + opts['public-key'] = params.pbk; + } + if (params.sid) { + opts['short-id'] = params.sid; + } + if (params.spx) { + opts['_spider-x'] = params.spx; + } + if (params.mode) { + proxy._mode = params.mode; + } + if (params.extra) { + proxy._extra = params.extra; + } + if (Object.keys(opts).length > 0) { + $set(proxy, params.security+"-opts", opts); + } + } + } + + proxy.udp = toBool(params["udp"]); + proxy.tfo = toBool(params["tfo"]); +} + +param = kv/single; + +kv = key:$[a-z]i+ "=" value:$[^&#]i* { + params[key] = value; +} + +single = key:$[a-z]i+ { + params[key] = true; +}; + +name = "#" + match:$.* { + return decodeURIComponent(match); +} +`; +let parser; +export default function getParser() { + if (!parser) { + parser = peggy.generate(grammars); + } + return parser; +} diff --git a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg new file mode 100644 index 0000000000..c97d8e9e76 --- /dev/null +++ b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg @@ -0,0 +1,158 @@ +// global initializer +{{ + function $set(obj, path, value) { + if (Object(obj) !== obj) return obj; + if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; + path + .slice(0, -1) + .reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[ + path[path.length - 1] + ] = value; + return obj; + } + + function toBool(str) { + if (typeof str === 'undefined' || str === null) return undefined; + return /(TRUE)|1/i.test(str); + } +}} + +{ + const proxy = {}; + const obfs = {}; + const $ = {}; + const params = {}; +} + +start = (trojan) { + return proxy +} + +trojan = "trojan://" password:password "@" server:server ":" port:port "/"? params? name:name?{ + proxy.type = "trojan"; + proxy.password = password; + proxy.server = server; + proxy.port = port; + proxy.name = name; + + // name may be empty + if (!proxy.name) { + proxy.name = server + ":" + port; + } +}; + +password = match:$[^@]+ { + return decodeURIComponent(match); +}; + +server = ip/domain; + +domain = match:[0-9a-zA-z-_.]+ { + const domain = match.join(""); + if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) { + return domain; + } +} + +ip = & { + const start = peg$currPos; + let end; + let j = start; + while (j < input.length) { + if (input[j] === ",") break; + if (input[j] === ":") end = j; + j++; + } + peg$currPos = end || j; + $.ip = input.substring(start, end).trim(); + return true; +} { return $.ip; } + +port = digits:[0-9]+ { + const port = parseInt(digits.join(""), 10); + if (port >= 0 && port <= 65535) { + return port; + } else { + throw new Error("Invalid port: " + port); + } +} + +params = "?" head:param tail:("&"@param)* { + for (const [key, value] of Object.entries(params)) { + params[key] = decodeURIComponent(value); + } + proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); + proxy.sni = params["sni"] || params["peer"]; + proxy['client-fingerprint'] = params.fp; + proxy.alpn = params.alpn ? decodeURIComponent(params.alpn).split(',') : undefined; + + if (toBool(params["ws"])) { + proxy.network = "ws"; + $set(proxy, "ws-opts.path", params["wspath"]); + } + + if (params["type"]) { + let httpupgrade + proxy.network = params["type"] + if(proxy.network === 'httpupgrade') { + proxy.network = 'ws' + httpupgrade = true + } + if (['grpc'].includes(proxy.network)) { + proxy[proxy.network + '-opts'] = { + 'grpc-service-name': params["serviceName"], + '_grpc-type': params["mode"], + '_grpc-authority': params["authority"], + }; + } else { + if (params["path"]) { + $set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"])); + } + if (params["host"]) { + $set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"])); + } + if (httpupgrade) { + $set(proxy, proxy.network+"-opts.v2ray-http-upgrade", true); + $set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true); + } + } + if (['reality'].includes(params.security)) { + const opts = {}; + if (params.pbk) { + opts['public-key'] = params.pbk; + } + if (params.sid) { + opts['short-id'] = params.sid; + } + if (params.spx) { + opts['_spider-x'] = params.spx; + } + if (params.mode) { + proxy._mode = params.mode; + } + if (params.extra) { + proxy._extra = params.extra; + } + if (Object.keys(opts).length > 0) { + $set(proxy, params.security+"-opts", opts); + } + } + } + + proxy.udp = toBool(params["udp"]); + proxy.tfo = toBool(params["tfo"]); +} + +param = kv/single; + +kv = key:$[a-z]i+ "=" value:$[^&#]i* { + params[key] = value; +} + +single = key:$[a-z]i+ { + params[key] = true; +}; + +name = "#" + match:$.* { + return decodeURIComponent(match); +} \ No newline at end of file diff --git a/backend/src/core/proxy-utils/preprocessors/index.js b/backend/src/core/proxy-utils/preprocessors/index.js new file mode 100644 index 0000000000..d9145bfecf --- /dev/null +++ b/backend/src/core/proxy-utils/preprocessors/index.js @@ -0,0 +1,166 @@ +import { safeLoad } from '@/utils/yaml'; +import { Base64 } from 'js-base64'; +import $ from '@/core/app'; + +function HTML() { + const name = 'HTML'; + const test = (raw) => /^/.test(raw); + // simply discard HTML + const parse = () => ''; + return { name, test, parse }; +} + +function Base64Encoded() { + const name = 'Base64 Pre-processor'; + + const keys = [ + 'dm1lc3M', // vmess + 'c3NyOi8v', // ssr:// + 'c29ja3M6Ly', // socks:// + 'dHJvamFu', // trojan + 'c3M6Ly', // ss:/ + 'c3NkOi8v', // ssd:// + 'c2hhZG93', // shadow + 'aHR0c', // htt + 'dmxlc3M=', // vless + 'aHlzdGVyaWEy', // hysteria2 + 'aHkyOi8v', // hy2:// + 'd2lyZWd1YXJkOi8v', // wireguard:// + 'd2c6Ly8=', // wg:// + 'dHVpYzovLw==', // tuic:// + ]; + + const test = function (raw) { + return ( + !/^\w+:\/\/\w+/im.test(raw) && + keys.some((k) => raw.indexOf(k) !== -1) + ); + }; + const parse = function (raw) { + const decoded = Base64.decode(raw); + if (!/^\w+(:\/\/|\s*?=\s*?)\w+/m.test(decoded)) { + $.error( + `Base64 Pre-processor error: decoded line does not start with protocol`, + ); + return raw; + } + + return decoded; + }; + return { name, test, parse }; +} + +function Clash() { + const name = 'Clash Pre-processor'; + const test = function (raw) { + if (!/proxies/.test(raw)) return false; + const content = safeLoad(raw); + return content.proxies && Array.isArray(content.proxies); + }; + const parse = function (raw, includeProxies) { + // Clash YAML format + + // 防止 VLESS节点 reality-opts 选项中的 short-id 被解析成 Infinity + // 匹配 short-id 冒号后面的值(包含空格和引号) + const afterReplace = raw.replace( + /short-id:([ \t]*[^#\n,}]*)/g, + (matched, value) => { + const afterTrim = value.trim(); + + // 为空 + if (!afterTrim || afterTrim === '') { + return 'short-id: ""'; + } + + // 是否被引号包裹 + if (/^(['"]).*\1$/.test(afterTrim)) { + return `short-id: ${afterTrim}`; + } else if (['null'].includes(afterTrim)) { + return `short-id: ${afterTrim}`; + } else { + return `short-id: "${afterTrim}"`; + } + }, + ); + + const { + proxies, + 'global-client-fingerprint': globalClientFingerprint, + } = safeLoad(afterReplace); + return ( + (includeProxies ? 'proxies:\n' : '') + + proxies + .map((p) => { + // https://github.com/MetaCubeX/mihomo/blob/Alpha/docs/config.yaml#L73C1-L73C26 + if (globalClientFingerprint && !p['client-fingerprint']) { + p['client-fingerprint'] = globalClientFingerprint; + } + return `${includeProxies ? ' - ' : ''}${JSON.stringify( + p, + )}\n`; + }) + .join('') + ); + }; + return { name, test, parse }; +} + +function SSD() { + const name = 'SSD Pre-processor'; + const test = function (raw) { + return raw.indexOf('ssd://') === 0; + }; + const parse = function (raw) { + // preprocessing for SSD subscription format + const output = []; + let ssdinfo = JSON.parse(Base64.decode(raw.split('ssd://')[1])); + let port = ssdinfo.port; + let method = ssdinfo.encryption; + let password = ssdinfo.password; + // servers config + let servers = ssdinfo.servers; + for (let i = 0; i < servers.length; i++) { + let server = servers[i]; + method = server.encryption ? server.encryption : method; + password = server.password ? server.password : password; + let userinfo = Base64.encode(method + ':' + password); + let hostname = server.server; + port = server.port ? server.port : port; + let tag = server.remarks ? server.remarks : i; + let plugin = server.plugin_options + ? '/?plugin=' + + encodeURIComponent( + server.plugin + ';' + server.plugin_options, + ) + : ''; + output[i] = + 'ss://' + + userinfo + + '@' + + hostname + + ':' + + port + + plugin + + '#' + + tag; + } + return output.join('\n'); + }; + return { name, test, parse }; +} + +function FullConfig() { + const name = 'Full Config Preprocessor'; + const test = function (raw) { + return /^(\[server_local\]|\[Proxy\])/gm.test(raw); + }; + const parse = function (raw) { + const match = raw.match( + /^\[server_local|Proxy\]([\s\S]+?)^\[.+?\](\r?\n|$)/im, + )?.[1]; + return match || raw; + }; + return { name, test, parse }; +} + +export default [HTML(), Clash(), Base64Encoded(), SSD(), FullConfig()]; diff --git a/backend/src/core/proxy-utils/processors/index.js b/backend/src/core/proxy-utils/processors/index.js new file mode 100644 index 0000000000..a155d36d99 --- /dev/null +++ b/backend/src/core/proxy-utils/processors/index.js @@ -0,0 +1,1190 @@ +import resourceCache from '@/utils/resource-cache'; +import scriptResourceCache from '@/utils/script-resource-cache'; +import { isIPv4, isIPv6, ipAddress } from '@/utils'; +import { FULL } from '@/utils/logical'; +import { getFlag, removeFlag } from '@/utils/geo'; +import { doh } from '@/utils/dns'; +import lodash from 'lodash'; +import $ from '@/core/app'; +import { hex_md5 } from '@/vendor/md5'; +import { ProxyUtils } from '@/core/proxy-utils'; +import { produceArtifact } from '@/restful/sync'; +import { SETTINGS_KEY } from '@/constants'; +import YAML from '@/utils/yaml'; + +import env from '@/utils/env'; +import { + getFlowField, + getFlowHeaders, + parseFlowHeaders, + validCheck, + flowTransfer, + getRmainingDays, + normalizeFlowHeader, +} from '@/utils/flow'; + +function isObject(item) { + return item && typeof item === 'object' && !Array.isArray(item); +} +function trimWrap(str) { + if (str.startsWith('<') && str.endsWith('>')) { + return str.slice(1, -1); + } + return str; +} +function deepMerge(target, _other) { + const other = typeof _other === 'string' ? JSON.parse(_other) : _other; + for (const key in other) { + if (isObject(other[key])) { + if (key.endsWith('!')) { + const k = trimWrap(key.slice(0, -1)); + target[k] = other[key]; + } else { + const k = trimWrap(key); + if (!target[k]) Object.assign(target, { [k]: {} }); + deepMerge(target[k], other[k]); + } + } else if (Array.isArray(other[key])) { + if (key.startsWith('+')) { + const k = trimWrap(key.slice(1)); + if (!target[k]) Object.assign(target, { [k]: [] }); + target[k] = [...other[key], ...target[k]]; + } else if (key.endsWith('+')) { + const k = trimWrap(key.slice(0, -1)); + if (!target[k]) Object.assign(target, { [k]: [] }); + target[k] = [...target[k], ...other[key]]; + } else { + const k = trimWrap(key); + Object.assign(target, { [k]: other[key] }); + } + } else { + Object.assign(target, { [key]: other[key] }); + } + } + return target; +} +/** + The rule "(name CONTAINS "🇨🇳") AND (port IN [80, 443])" can be expressed as follows: + { + operator: "AND", + child: [ + { + attr: "name", + proposition: "CONTAINS", + value: "🇨🇳" + }, + { + attr: "port", + proposition: "IN", + value: [80, 443] + } + ] +} + */ + +function ConditionalFilter({ rule }) { + return { + name: 'Conditional Filter', + func: (proxies) => { + return proxies.map((proxy) => isMatch(rule, proxy)); + }, + }; +} + +function isMatch(rule, proxy) { + // leaf node + if (!rule.operator) { + switch (rule.proposition) { + case 'IN': + return rule.value.indexOf(proxy[rule.attr]) !== -1; + case 'CONTAINS': + if (typeof proxy[rule.attr] !== 'string') return false; + return proxy[rule.attr].indexOf(rule.value) !== -1; + case 'EQUALS': + return proxy[rule.attr] === rule.value; + case 'EXISTS': + return ( + proxy[rule.attr] !== null || + typeof proxy[rule.attr] !== 'undefined' + ); + default: + throw new Error(`Unknown proposition: ${rule.proposition}`); + } + } + + // operator nodes + switch (rule.operator) { + case 'AND': + return rule.child.every((child) => isMatch(child, proxy)); + case 'OR': + return rule.child.some((child) => isMatch(child, proxy)); + case 'NOT': + return !isMatch(rule.child, proxy); + default: + throw new Error(`Unknown operator: ${rule.operator}`); + } +} + +function QuickSettingOperator(args) { + return { + name: 'Quick Setting Operator', + func: (proxies) => { + if (get(args.useless)) { + const filter = UselessFilter(); + const selected = filter.func(proxies); + proxies = proxies.filter( + (p, i) => selected[i] && p.port > 0 && p.port <= 65535, + ); + } + + return proxies.map((proxy) => { + proxy.udp = get(args.udp, proxy.udp); + proxy.tfo = get(args.tfo, proxy.tfo); + proxy['fast-open'] = get(args.tfo, proxy['fast-open']); + proxy['skip-cert-verify'] = get( + args.scert, + proxy['skip-cert-verify'], + ); + if (proxy.type === 'vmess') { + proxy.aead = get(args['vmess aead'], proxy.aead); + } + return proxy; + }); + }, + }; + + function get(value, defaultValue) { + switch (value) { + case 'ENABLED': + return true; + case 'DISABLED': + return false; + default: + return defaultValue; + } + } +} + +// add or remove flag for proxies +function FlagOperator({ mode, tw }) { + return { + name: 'Flag Operator', + func: (proxies) => { + return proxies.map((proxy) => { + if (mode === 'remove') { + // no flag + proxy.name = removeFlag(proxy.name); + } else { + // get flag + const newFlag = getFlag(proxy.name); + // remove old flag + proxy.name = removeFlag(proxy.name); + proxy.name = newFlag + ' ' + proxy.name; + if (tw == 'ws') { + proxy.name = proxy.name.replace(/🇹🇼/g, '🇼🇸'); + } else if (tw == 'tw') { + // 不变 + } else { + proxy.name = proxy.name.replace(/🇹🇼/g, '🇨🇳'); + } + } + return proxy; + }); + }, + }; +} + +// duplicate handler +function HandleDuplicateOperator(arg) { + const { action, template, link, position } = { + ...{ + action: 'rename', + template: '0 1 2 3 4 5 6 7 8 9', + link: '-', + position: 'back', + }, + ...arg, + }; + return { + name: 'Handle Duplicate Operator', + func: (proxies) => { + if (action === 'delete') { + const chosen = {}; + return proxies.filter((p) => { + if (chosen[p.name]) { + return false; + } + chosen[p.name] = true; + return true; + }); + } else if (action === 'rename') { + const numbers = template.split(' '); + // count occurrences of each name + const counter = {}; + let maxLen = 0; + proxies.forEach((p) => { + if (typeof counter[p.name] === 'undefined') + counter[p.name] = 1; + else counter[p.name]++; + maxLen = Math.max( + counter[p.name].toString().length, + maxLen, + ); + }); + const increment = {}; + return proxies.map((p) => { + if (counter[p.name] > 1) { + if (typeof increment[p.name] == 'undefined') + increment[p.name] = 1; + let num = ''; + let cnt = increment[p.name]++; + let numDigits = 0; + while (cnt > 0) { + num = numbers[cnt % 10] + num; + cnt = parseInt(cnt / 10); + numDigits++; + } + // padding + while (numDigits++ < maxLen) { + num = numbers[0] + num; + } + if (position === 'front') { + p.name = num + link + p.name; + } else if (position === 'back') { + p.name = p.name + link + num; + } + } + return p; + }); + } + }, + }; +} + +// sort proxies according to their names +function SortOperator(order = 'asc') { + return { + name: 'Sort Operator', + func: (proxies) => { + switch (order) { + case 'asc': + case 'desc': + return proxies.sort((a, b) => { + let res = a.name > b.name ? 1 : -1; + res *= order === 'desc' ? -1 : 1; + return res; + }); + case 'random': + return shuffle(proxies); + default: + throw new Error('Unknown sort option: ' + order); + } + }, + }; +} + +// sort by regex +function RegexSortOperator(input) { + const order = input.order || 'asc'; + let expressions = input.expressions; + if (Array.isArray(input)) { + expressions = input; + } + if (!Array.isArray(expressions)) { + expressions = []; + } + return { + name: 'Regex Sort Operator', + func: (proxies) => { + expressions = expressions.map((expr) => buildRegex(expr)); + return proxies.sort((a, b) => { + const oA = getRegexOrder(expressions, a.name); + const oB = getRegexOrder(expressions, b.name); + if (oA && !oB) return -1; + if (oB && !oA) return 1; + if (oA && oB) return oA < oB ? -1 : 1; + if (order === 'original') { + return 0; + } else if (order === 'desc') { + return a.name < b.name ? 1 : -1; + } else { + return a.name < b.name ? -1 : 1; + } + }); + }, + }; +} + +function getRegexOrder(expressions, str) { + let order = null; + for (let i = 0; i < expressions.length; i++) { + if (expressions[i].test(str)) { + order = i + 1; // plus 1 is important! 0 will be treated as false!!! + break; + } + } + return order; +} + +// rename by regex +// keywords: [{expr: "string format regex", now: "now"}] +function RegexRenameOperator(regex) { + return { + name: 'Regex Rename Operator', + func: (proxies) => { + return proxies.map((proxy) => { + for (const { expr, now } of regex) { + proxy.name = proxy.name + .replace(buildRegex(expr, 'g'), now) + .trim(); + } + return proxy; + }); + }, + }; +} + +// delete regex operator +// regex: ['a', 'b', 'c'] +function RegexDeleteOperator(regex) { + const regex_ = regex.map((r) => { + return { + expr: r, + now: '', + }; + }); + return { + name: 'Regex Delete Operator', + func: RegexRenameOperator(regex_).func, + }; +} + +/** Script Operator + function operator(proxies) { + const {arg1} = $arguments; + + // do something + return proxies; + } + + WARNING: + 1. This function name should be `operator`! + 2. Always declare variables before using them! + */ +function ScriptOperator(script, targetPlatform, $arguments, source, $options) { + return { + name: 'Script Operator', + func: async (proxies) => { + let output = proxies; + if (output?.$file?.type === 'mihomoProfile') { + try { + let patch = YAML.safeLoad(script); + let config; + if (output?.$content) { + try { + config = YAML.safeLoad(output?.$content); + } catch (e) { + $.error(e.message ?? e); + } + } + // if (typeof patch !== 'object') patch = {}; + if (typeof patch !== 'object') + throw new Error('patch is not an object'); + output.$content = ProxyUtils.yaml.safeDump( + deepMerge( + config || + (output?.$file?.sourceType === 'none' + ? {} + : { + proxies: await produceArtifact({ + type: + output?.$file?.sourceType || + 'collection', + name: output?.$file?.sourceName, + platform: 'mihomo', + produceType: 'internal', + produceOpts: { + 'delete-underscore-fields': true, + }, + }), + }), + patch, + ), + ); + return output; + } catch (e) { + // console.log(e); + } + } + await (async function () { + const operator = createDynamicFunction( + 'operator', + script, + $arguments, + $options, + ); + output = operator(proxies, targetPlatform, { source, ...env }); + })(); + return output; + }, + nodeFunc: async (proxies) => { + let output = proxies; + await (async function () { + const operator = createDynamicFunction( + 'operator', + `async function operator(input = []) { + if (input && (input.$files || input.$content)) { + let { $content, $files, $options, $file } = input + if($file.type === 'mihomoProfile') { + ${script} + if(typeof main === 'function') { + let config; + if ($content) { + try { + config = ProxyUtils.yaml.safeLoad($content); + } catch (e) { + console.log(e.message ?? e); + } + } + $content = ProxyUtils.yaml.safeDump(await main(config || ($file.sourceType === 'none' ? {} : { + proxies: await produceArtifact({ + type: $file.sourceType || 'collection', + name: $file.sourceName, + platform: 'mihomo', + produceType: 'internal', + produceOpts: { + 'delete-underscore-fields': true + } + }), + }))) + } + } else { + ${script} + } + return { $content, $files, $options, $file } + } else { + let proxies = input + let list = [] + for await (let $server of proxies) { + ${script} + list.push($server) + } + return list + } + }`, + $arguments, + $options, + ); + output = operator(proxies, targetPlatform, { source, ...env }); + })(); + return output; + }, + }; +} + +function parseIP4P(IP4P) { + let server; + let port; + try { + let array = IP4P.split(':'); + + port = parseInt(array[2], 16); + let ipab = parseInt(array[3], 16); + let ipcd = parseInt(array[4], 16); + let ipa = ipab >> 8; + let ipb = ipab & 0xff; + let ipc = ipcd >> 8; + let ipd = ipcd & 0xff; + server = `${ipa}.${ipb}.${ipc}.${ipd}`; + if (port <= 0 || port > 65535) { + throw new Error(`Invalid port number: ${port}`); + } + if (!isIPv4(server)) { + throw new Error(`Invalid IP address: ${server}`); + } + } catch (e) { + // throw new Error(`IP4P 解析失败: ${e}`); + $.error(`IP4P 解析失败: ${e}`); + } + return { server, port }; +} + +const DOMAIN_RESOLVERS = { + Custom: async function (domain, type, noCache, timeout, edns, url) { + const id = hex_md5(`CUSTOM:${url}:${domain}:${type}`); + const cached = resourceCache.get(id); + if (!noCache && cached) return cached; + const answerType = type === 'IPv6' ? 'AAAA' : 'A'; + const res = await doh({ + url, + domain, + type: answerType, + timeout, + edns, + }); + + const { answers } = res; + if (!Array.isArray(answers) || answers.length === 0) { + throw new Error('No answers'); + } + const result = answers + .filter((i) => i?.type === answerType) + .map((i) => i?.data) + .filter((i) => i); + if (result.length === 0) { + throw new Error('No answers'); + } + resourceCache.set(id, result); + return result; + }, + Google: async function (domain, type, noCache, timeout, edns) { + const id = hex_md5(`GOOGLE:${domain}:${type}`); + const cached = resourceCache.get(id); + if (!noCache && cached) return cached; + const answerType = type === 'IPv6' ? 'AAAA' : 'A'; + const res = await doh({ + url: 'https://8.8.4.4/dns-query', + domain, + type: answerType, + timeout, + edns, + }); + + const { answers } = res; + if (!Array.isArray(answers) || answers.length === 0) { + throw new Error('No answers'); + } + const result = answers + .filter((i) => i?.type === answerType) + .map((i) => i?.data) + .filter((i) => i); + if (result.length === 0) { + throw new Error('No answers'); + } + resourceCache.set(id, result); + return result; + }, + 'IP-API': async function (domain, type, noCache, timeout) { + if (['IPv6'].includes(type)) { + throw new Error(`域名解析服务提供方 IP-API 不支持 ${type}`); + } + const id = hex_md5(`IP-API:${domain}`); + const cached = resourceCache.get(id); + if (!noCache && cached) return cached; + const resp = await $.http.get({ + url: `http://ip-api.com/json/${encodeURIComponent( + domain, + )}?lang=zh-CN`, + timeout, + }); + const body = JSON.parse(resp.body); + if (body['status'] !== 'success') { + throw new Error(`Status is ${body['status']}`); + } + if (!body.query || body.query === 0) { + throw new Error('No answers'); + } + const result = [body.query]; + if (result.length === 0) { + throw new Error('No answers'); + } + resourceCache.set(id, result); + return result; + }, + Cloudflare: async function (domain, type, noCache, timeout, edns) { + const id = hex_md5(`CLOUDFLARE:${domain}:${type}`); + const cached = resourceCache.get(id); + if (!noCache && cached) return cached; + const answerType = type === 'IPv6' ? 'AAAA' : 'A'; + const res = await doh({ + url: 'https://1.0.0.1/dns-query', + domain, + type: answerType, + timeout, + edns, + }); + + const { answers } = res; + if (!Array.isArray(answers) || answers.length === 0) { + throw new Error('No answers'); + } + const result = answers + .filter((i) => i?.type === answerType) + .map((i) => i?.data) + .filter((i) => i); + if (result.length === 0) { + throw new Error('No answers'); + } + resourceCache.set(id, result); + return result; + }, + Ali: async function (domain, type, noCache, timeout, edns) { + const id = hex_md5(`ALI:${domain}:${type}`); + const cached = resourceCache.get(id); + if (!noCache && cached) return cached; + const resp = await $.http.get({ + url: `http://223.6.6.6/resolve?edns_client_subnet=${edns}/24&name=${encodeURIComponent( + domain, + )}&type=${type === 'IPv6' ? 'AAAA' : 'A'}&short=1`, + headers: { + accept: 'application/dns-json', + }, + timeout, + }); + const answers = JSON.parse(resp.body); + if (!Array.isArray(answers) || answers.length === 0) { + throw new Error('No answers'); + } + const result = answers; + if (result.length === 0) { + throw new Error('No answers'); + } + resourceCache.set(id, result); + return result; + }, + Tencent: async function (domain, type, noCache, timeout, edns) { + const id = hex_md5(`TENCENT:${domain}:${type}`); + const cached = resourceCache.get(id); + if (!noCache && cached) return cached; + const resp = await $.http.get({ + url: `http://119.28.28.28/d?ip=${edns}&type=${ + type === 'IPv6' ? 'AAAA' : 'A' + }&dn=${encodeURIComponent(domain)}`, + headers: { + accept: 'application/dns-json', + }, + timeout, + }); + const answers = resp.body.split(';').map((i) => i.split(',')[0]); + if (answers.length === 0 || String(answers) === '0') { + throw new Error('No answers'); + } + const result = answers; + if (result.length === 0) { + throw new Error('No answers'); + } + resourceCache.set(id, result); + return result; + }, +}; + +function ResolveDomainOperator({ + provider, + type: _type, + filter, + cache, + url, + timeout, + edns: _edns, +}) { + if (['IPv6', 'IP4P'].includes(_type) && ['IP-API'].includes(provider)) { + throw new Error(`域名解析服务提供方 ${provider} 不支持 ${_type}`); + } + const { defaultTimeout } = $.read(SETTINGS_KEY); + const requestTimeout = timeout || defaultTimeout || 8000; + let type = ['IPv6', 'IP4P'].includes(_type) ? 'IPv6' : 'IPv4'; + + const resolver = DOMAIN_RESOLVERS[provider]; + if (!resolver) { + throw new Error(`找不到域名解析服务提供方: ${provider}`); + } + let edns = _edns || '223.6.6.6'; + if (!isIP(edns)) throw new Error(`域名解析 EDNS 应为 IP`); + $.info( + `Domain Resolver: [${_type}] ${provider} ${edns || ''} ${url || ''}`, + ); + return { + name: 'Resolve Domain Operator', + func: async (proxies) => { + proxies.forEach((p, i) => { + if (!p['_no-resolve'] && p['no-resolve']) { + proxies[i]['_no-resolve'] = p['no-resolve']; + } + }); + const results = {}; + const limit = 15; // more than 20 concurrency may result in surge TCP connection shortage. + const totalDomain = [ + ...new Set( + proxies + .filter((p) => !isIP(p.server) && !p['_no-resolve']) + .map((c) => c.server), + ), + ]; + const totalBatch = Math.ceil(totalDomain.length / limit); + for (let i = 0; i < totalBatch; i++) { + const currentBatch = []; + for (let domain of totalDomain.splice(0, limit)) { + currentBatch.push( + resolver( + domain, + type, + cache === 'disabled', + requestTimeout, + edns, + url, + ) + .then((ip) => { + results[domain] = ip; + $.info( + `Successfully resolved domain: ${domain} ➟ ${ip}`, + ); + }) + .catch((err) => { + $.error( + `Failed to resolve domain: ${domain} with resolver [${provider}]: ${err}`, + ); + }), + ); + } + await Promise.all(currentBatch); + } + proxies.forEach((p) => { + if (!p['_no-resolve']) { + if (results[p.server]) { + p._resolved_ips = results[p.server]; + let ip = Array.isArray(results[p.server]) + ? results[p.server][ + Math.floor( + Math.random() * results[p.server].length, + ) + ] + : results[p.server]; + if (type === 'IPv6' && isIPv6(ip)) { + try { + ip = new ipAddress.Address6(ip).correctForm(); + } catch (e) { + $.error( + `Failed to parse IPv6 address: ${ip}: ${e}`, + ); + } + if (/^2001::[^:]+:[^:]+:[^:]+$/.test(ip)) { + p._IP4P = ip; + const { server, port } = parseIP4P(ip); + if (server && port) { + p._domain = p.server; + p.server = server; + p.port = port; + p.resolved = true; + p._IPv4 = p.server; + if (!isIP(p._IP)) { + p._IP = p.server; + } + } else if (!p.resolved) { + p.resolved = false; + } + } else { + p._domain = p.server; + p.server = ip; + p.resolved = true; + p[`_${type}`] = p.server; + if (!isIP(p._IP)) { + p._IP = p.server; + } + } + } else { + p._domain = p.server; + p.server = ip; + p.resolved = true; + p[`_${type}`] = p.server; + if (!isIP(p._IP)) { + p._IP = p.server; + } + } + } else if (!p.resolved) { + p.resolved = false; + } + } + }); + + return proxies.filter((p) => { + if (filter === 'removeFailed') { + return isIP(p.server) || p['_no-resolve'] || p.resolved; + } else if (filter === 'IPOnly') { + return isIP(p.server); + } else if (filter === 'IPv4Only') { + return isIPv4(p.server); + } else if (filter === 'IPv6Only') { + return isIPv6(p.server); + } else { + return true; + } + }); + }, + }; +} + +function isIP(ip) { + return isIPv4(ip) || isIPv6(ip); +} + +ResolveDomainOperator.resolver = DOMAIN_RESOLVERS; + +function isAscii(str) { + // eslint-disable-next-line no-control-regex + var pattern = /^[\x00-\x7F]+$/; // ASCII 范围的 Unicode 编码 + return pattern.test(str); +} + +/**************************** Filters ***************************************/ +// filter useless proxies +function UselessFilter() { + return { + name: 'Useless Filter', + func: (proxies) => { + return proxies.map((proxy) => { + if (proxy.cipher && !isAscii(proxy.cipher)) { + return false; + } else if (proxy.password && !isAscii(proxy.password)) { + return false; + } else { + if (proxy.network) { + let transportHosts = + proxy[`${proxy.network}-opts`]?.headers?.Host || + proxy[`${proxy.network}-opts`]?.headers?.host; + transportHosts = Array.isArray(transportHosts) + ? transportHosts + : [transportHosts]; + if ( + transportHosts.some( + (host) => host && !isAscii(host), + ) + ) { + return false; + } + } + return !/网址|流量|时间|应急|过期|Bandwidth|expire/.test( + proxy.name, + ); + } + }); + }, + }; +} + +// filter by regions +function RegionFilter(input) { + let regions = input?.value || input; + if (!Array.isArray(regions)) { + regions = []; + } + const keep = input?.keep ?? true; + const REGION_MAP = { + HK: '🇭🇰', + TW: '🇹🇼', + US: '🇺🇸', + SG: '🇸🇬', + JP: '🇯🇵', + UK: '🇬🇧', + DE: '🇩🇪', + KR: '🇰🇷', + }; + return { + name: 'Region Filter', + func: (proxies) => { + // this would be high memory usage + return proxies.map((proxy) => { + const flag = getFlag(proxy.name); + const selected = regions.some((r) => REGION_MAP[r] === flag); + return keep ? selected : !selected; + }); + }, + }; +} + +// filter by regex +function RegexFilter({ regex = [], keep = true }) { + return { + name: 'Regex Filter', + func: (proxies) => { + return proxies.map((proxy) => { + const selected = regex.some((r) => { + return buildRegex(r).test(proxy.name); + }); + return keep ? selected : !selected; + }); + }, + }; +} + +function buildRegex(str, ...options) { + options = options.join(''); + if (str.startsWith('(?i)')) { + str = str.substring(4); + return new RegExp(str, 'i' + options); + } else { + return new RegExp(str, options); + } +} + +// filter by proxy types +function TypeFilter(input) { + let types = input?.value || input; + if (!Array.isArray(types)) { + types = []; + } + const keep = input?.keep ?? true; + return { + name: 'Type Filter', + func: (proxies) => { + return proxies.map((proxy) => { + const selected = types.some((t) => proxy.type === t); + return keep ? selected : !selected; + }); + }, + }; +} + +/** + Script Example + + function filter(proxies) { + return proxies.map(p => { + return p.name.indexOf('🇭🇰') !== -1; + }); + } + + WARNING: + 1. This function name should be `filter`! + 2. Always declare variables before using them! + */ +function ScriptFilter(script, targetPlatform, $arguments, source, $options) { + return { + name: 'Script Filter', + func: async (proxies) => { + let output = FULL(proxies.length, true); + await (async function () { + const filter = createDynamicFunction( + 'filter', + script, + $arguments, + $options, + ); + output = filter(proxies, targetPlatform, { source, ...env }); + })(); + return output; + }, + nodeFunc: async (proxies) => { + let output = FULL(proxies.length, true); + await (async function () { + const filter = createDynamicFunction( + 'filter', + `async function filter(input = []) { + let proxies = input + let list = [] + const fn = async ($server) => { + ${script} + } + for await (let $server of proxies) { + list.push(await fn($server)) + } + return list + }`, + $arguments, + $options, + ); + output = filter(proxies, targetPlatform, { source, ...env }); + })(); + return output; + }, + }; +} + +export default { + 'Useless Filter': UselessFilter, + 'Region Filter': RegionFilter, + 'Regex Filter': RegexFilter, + 'Type Filter': TypeFilter, + 'Script Filter': ScriptFilter, + 'Conditional Filter': ConditionalFilter, + + 'Quick Setting Operator': QuickSettingOperator, + 'Flag Operator': FlagOperator, + 'Sort Operator': SortOperator, + 'Regex Sort Operator': RegexSortOperator, + 'Regex Rename Operator': RegexRenameOperator, + 'Regex Delete Operator': RegexDeleteOperator, + 'Script Operator': ScriptOperator, + 'Handle Duplicate Operator': HandleDuplicateOperator, + 'Resolve Domain Operator': ResolveDomainOperator, +}; + +async function ApplyFilter(filter, objs) { + // select proxies + let selected = FULL(objs.length, true); + try { + selected = await filter.func(objs); + } catch (err) { + let funcErr = ''; + let funcErrMsg = `${err.message ?? err}`; + if (funcErrMsg.includes('$server is not defined')) { + funcErr = ''; + } else { + $.error( + `Cannot apply filter ${filter.name}(function filter)! Reason: ${err}`, + ); + funcErr = `执行 function filter 失败 ${funcErrMsg}; `; + } + try { + selected = await filter.nodeFunc(objs); + } catch (err) { + $.error( + `Cannot apply filter ${filter.name}(shortcut script)! Reason: ${err}`, + ); + let nodeErr = ''; + let nodeErrMsg = `${err.message ?? err}`; + if (funcErr && nodeErrMsg === funcErrMsg) { + nodeErr = ''; + funcErr = `执行失败 ${funcErrMsg}`; + } else { + nodeErr = `执行快捷过滤脚本 失败 ${nodeErrMsg}`; + } + throw new Error(`脚本过滤 ${funcErr}${nodeErr}`); + } + } + return objs.filter((_, i) => selected[i]); +} + +async function ApplyOperator(operator, objs) { + let output = clone(objs); + try { + const output_ = await operator.func(output); + if (output_) output = output_; + } catch (err) { + let funcErr = ''; + let funcErrMsg = `${err.message ?? err}`; + if ( + funcErrMsg.includes('$server is not defined') || + funcErrMsg.includes('$content is not defined') || + funcErrMsg.includes('$files is not defined') || + output?.$files || + output?.$content + ) { + funcErr = ''; + } else { + $.error( + `Cannot apply operator ${operator.name}(function operator)! Reason: ${err}`, + ); + funcErr = `执行 function operator 失败 ${funcErrMsg}; `; + } + try { + const output_ = await operator.nodeFunc(output); + if (output_) output = output_; + } catch (err) { + $.error( + `Cannot apply operator ${operator.name}(shortcut script)! Reason: ${err}`, + ); + let nodeErr = ''; + let nodeErrMsg = `${err.message ?? err}`; + if (funcErr && nodeErrMsg === funcErrMsg) { + nodeErr = ''; + funcErr = `执行失败 ${funcErrMsg}`; + } else { + nodeErr = `执行快捷脚本 失败 ${nodeErrMsg}`; + } + throw new Error(`脚本操作 ${funcErr}${nodeErr}`); + } + } + return output; +} + +export async function ApplyProcessor(processor, objs) { + if (processor.name.indexOf('Filter') !== -1) { + return ApplyFilter(processor, objs); + } else if (processor.name.indexOf('Operator') !== -1) { + return ApplyOperator(processor, objs); + } +} + +// shuffle array +function shuffle(array) { + let currentIndex = array.length, + temporaryValue, + randomIndex; + + // While there remain elements to shuffle... + while (0 !== currentIndex) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; +} + +// deep clone object +function clone(object) { + return JSON.parse(JSON.stringify(object)); +} + +function createDynamicFunction(name, script, $arguments, $options) { + const flowUtils = { + getFlowField, + getFlowHeaders, + parseFlowHeaders, + flowTransfer, + validCheck, + getRmainingDays, + normalizeFlowHeader, + }; + if ($.env.isLoon) { + return new Function( + '$arguments', + '$options', + '$substore', + 'lodash', + '$persistentStore', + '$httpClient', + '$notification', + 'ProxyUtils', + 'scriptResourceCache', + 'flowUtils', + 'produceArtifact', + 'require', + `${script}\n return ${name}`, + )( + $arguments, + $options, + $, + lodash, + // eslint-disable-next-line no-undef + $persistentStore, + // eslint-disable-next-line no-undef + $httpClient, + // eslint-disable-next-line no-undef + $notification, + ProxyUtils, + scriptResourceCache, + flowUtils, + produceArtifact, + eval(`typeof require !== "undefined"`) ? require : undefined, + ); + } else { + return new Function( + '$arguments', + '$options', + '$substore', + 'lodash', + 'ProxyUtils', + 'scriptResourceCache', + 'flowUtils', + 'produceArtifact', + 'require', + `${script}\n return ${name}`, + )( + $arguments, + $options, + $, + lodash, + ProxyUtils, + scriptResourceCache, + flowUtils, + produceArtifact, + eval(`typeof require !== "undefined"`) ? require : undefined, + ); + } +} diff --git a/backend/src/core/proxy-utils/producers/clash.js b/backend/src/core/proxy-utils/producers/clash.js new file mode 100644 index 0000000000..f5940f6cd8 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/clash.js @@ -0,0 +1,194 @@ +import { isPresent } from '@/core/proxy-utils/producers/utils'; +import $ from '@/core/app'; + +export default function Clash_Producer() { + const type = 'ALL'; + const produce = (proxies, type, opts = {}) => { + // VLESS XTLS is not supported by Clash + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L532 + // github.com/Dreamacro/clash/pull/2891/files + // filter unsupported proxies + // https://clash.wiki/configuration/outbound.html#shadowsocks + const list = proxies + .filter((proxy) => { + if (opts['include-unsupported-proxy']) return true; + if ( + ![ + 'ss', + 'ssr', + 'vmess', + 'vless', + 'socks5', + 'http', + 'snell', + 'trojan', + 'wireguard', + ].includes(proxy.type) || + (proxy.type === 'ss' && + ![ + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'rc4-md5', + 'chacha20-ietf', + 'xchacha20', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305', + ].includes(proxy.cipher)) || + (proxy.type === 'snell' && String(proxy.version) === '4') || + (proxy.type === 'vless' && + (typeof proxy.flow !== 'undefined' || + proxy['reality-opts'])) + ) { + return false; + } else if (proxy['underlying-proxy'] || proxy['dialer-proxy']) { + $.error( + `Clash 不支持前置代理字段. 已过滤节点 ${proxy.name}`, + ); + return false; + } + return true; + }) + .map((proxy) => { + if (proxy.type === 'vmess') { + // handle vmess aead + if (isPresent(proxy, 'aead')) { + if (proxy.aead) { + proxy.alterId = 0; + } + delete proxy.aead; + } + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + // https://dreamacro.github.io/clash/configuration/outbound.html#vmess + if ( + isPresent(proxy, 'cipher') && + ![ + 'auto', + 'aes-128-gcm', + 'chacha20-poly1305', + 'none', + ].includes(proxy.cipher) + ) { + proxy.cipher = 'auto'; + } + } else if (proxy.type === 'wireguard') { + proxy.keepalive = + proxy.keepalive ?? proxy['persistent-keepalive']; + proxy['persistent-keepalive'] = proxy.keepalive; + proxy['preshared-key'] = + proxy['preshared-key'] ?? proxy['pre-shared-key']; + proxy['pre-shared-key'] = proxy['preshared-key']; + } else if (proxy.type === 'snell' && proxy.version < 3) { + delete proxy.udp; + } else if (proxy.type === 'vless') { + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + } + + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'http' + ) { + let httpPath = proxy['http-opts']?.path; + if ( + isPresent(proxy, 'http-opts.path') && + !Array.isArray(httpPath) + ) { + proxy['http-opts'].path = [httpPath]; + } + let httpHost = proxy['http-opts']?.headers?.Host; + if ( + isPresent(proxy, 'http-opts.headers.Host') && + !Array.isArray(httpHost) + ) { + proxy['http-opts'].headers.Host = [httpHost]; + } + } + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } + if (proxy['plugin-opts']?.tls) { + if (isPresent(proxy, 'skip-cert-verify')) { + proxy['plugin-opts']['skip-cert-verify'] = + proxy['skip-cert-verify']; + } + } + if ( + [ + 'trojan', + 'tuic', + 'hysteria', + 'hysteria2', + 'juicity', + 'anytls', + ].includes(proxy.type) + ) { + delete proxy.tls; + } + + if (proxy['tls-fingerprint']) { + proxy.fingerprint = proxy['tls-fingerprint']; + } + delete proxy['tls-fingerprint']; + + if (isPresent(proxy, 'tls') && typeof proxy.tls !== 'boolean') { + delete proxy.tls; + } + + delete proxy.subName; + delete proxy.collectionName; + delete proxy.id; + delete proxy.resolved; + delete proxy['no-resolve']; + if (type !== 'internal') { + for (const key in proxy) { + if (proxy[key] == null || /^_/i.test(key)) { + delete proxy[key]; + } + } + } + if ( + ['grpc'].includes(proxy.network) && + proxy[`${proxy.network}-opts`] + ) { + delete proxy[`${proxy.network}-opts`]['_grpc-type']; + delete proxy[`${proxy.network}-opts`]['_grpc-authority']; + } + return proxy; + }); + return type === 'internal' + ? list + : 'proxies:\n' + + list + .map((proxy) => ' - ' + JSON.stringify(proxy) + '\n') + .join(''); + }; + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/producers/clashmeta.js b/backend/src/core/proxy-utils/producers/clashmeta.js new file mode 100644 index 0000000000..41234992aa --- /dev/null +++ b/backend/src/core/proxy-utils/producers/clashmeta.js @@ -0,0 +1,256 @@ +import { isPresent } from '@/core/proxy-utils/producers/utils'; + +export default function ClashMeta_Producer() { + const type = 'ALL'; + const produce = (proxies, type, opts = {}) => { + const list = proxies + .filter((proxy) => { + if (opts['include-unsupported-proxy']) return true; + if (proxy.type === 'snell' && String(proxy.version) === '4') { + return false; + } else if (['juicity'].includes(proxy.type)) { + return false; + } else if ( + ['ss'].includes(proxy.type) && + ![ + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'aes-128-ccm', + 'aes-192-ccm', + 'aes-256-ccm', + 'aes-128-gcm-siv', + 'aes-256-gcm-siv', + 'chacha20-ietf', + 'chacha20', + 'xchacha20', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305', + 'chacha8-ietf-poly1305', + 'xchacha8-ietf-poly1305', + '2022-blake3-aes-128-gcm', + '2022-blake3-aes-256-gcm', + '2022-blake3-chacha20-poly1305', + 'lea-128-gcm', + 'lea-192-gcm', + 'lea-256-gcm', + 'rabbit128-poly1305', + 'aegis-128l', + 'aegis-256', + 'aez-384', + 'deoxys-ii-256-128', + 'rc4-md5', + 'none', + ].includes(proxy.cipher) + ) { + // https://wiki.metacubex.one/config/proxies/ss/#cipher + return false; + } + return true; + }) + .map((proxy) => { + if (proxy.type === 'vmess') { + // handle vmess aead + if (isPresent(proxy, 'aead')) { + if (proxy.aead) { + proxy.alterId = 0; + } + delete proxy.aead; + } + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400 + // https://stash.wiki/proxy-protocols/proxy-types#vmess + if ( + isPresent(proxy, 'cipher') && + ![ + 'auto', + 'none', + 'zero', + 'aes-128-gcm', + 'chacha20-poly1305', + ].includes(proxy.cipher) + ) { + proxy.cipher = 'auto'; + } + } else if (proxy.type === 'tuic') { + if (isPresent(proxy, 'alpn')) { + proxy.alpn = Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn]; + } else { + proxy.alpn = ['h3']; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + } + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197 + if ( + (!proxy.token || proxy.token.length === 0) && + !isPresent(proxy, 'version') + ) { + proxy.version = 5; + } + } else if (proxy.type === 'hysteria') { + // auth_str 将会在未来某个时候删除 但是有的机场不规范 + if ( + isPresent(proxy, 'auth_str') && + !isPresent(proxy, 'auth-str') + ) { + proxy['auth-str'] = proxy['auth_str']; + } + if (isPresent(proxy, 'alpn')) { + proxy.alpn = Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn]; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + } + } else if (proxy.type === 'wireguard') { + proxy.keepalive = + proxy.keepalive ?? proxy['persistent-keepalive']; + proxy['persistent-keepalive'] = proxy.keepalive; + proxy['preshared-key'] = + proxy['preshared-key'] ?? proxy['pre-shared-key']; + proxy['pre-shared-key'] = proxy['preshared-key']; + } else if (proxy.type === 'snell' && proxy.version < 3) { + delete proxy.udp; + } else if (proxy.type === 'vless') { + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + } else if (proxy.type === 'ss') { + if ( + isPresent(proxy, 'shadow-tls-password') && + !isPresent(proxy, 'plugin') + ) { + proxy.plugin = 'shadow-tls'; + proxy['plugin-opts'] = { + host: proxy['shadow-tls-sni'], + password: proxy['shadow-tls-password'], + version: proxy['shadow-tls-version'], + }; + delete proxy['shadow-tls-password']; + delete proxy['shadow-tls-sni']; + delete proxy['shadow-tls-version']; + } + } + + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'http' + ) { + let httpPath = proxy['http-opts']?.path; + if ( + isPresent(proxy, 'http-opts.path') && + !Array.isArray(httpPath) + ) { + proxy['http-opts'].path = [httpPath]; + } + let httpHost = proxy['http-opts']?.headers?.Host; + if ( + isPresent(proxy, 'http-opts.headers.Host') && + !Array.isArray(httpHost) + ) { + proxy['http-opts'].headers.Host = [httpHost]; + } + } + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } + + if (proxy['plugin-opts']?.tls) { + if (isPresent(proxy, 'skip-cert-verify')) { + proxy['plugin-opts']['skip-cert-verify'] = + proxy['skip-cert-verify']; + } + } + if ( + [ + 'trojan', + 'tuic', + 'hysteria', + 'hysteria2', + 'juicity', + 'anytls', + ].includes(proxy.type) + ) { + delete proxy.tls; + } + + if (proxy['tls-fingerprint']) { + proxy.fingerprint = proxy['tls-fingerprint']; + } + delete proxy['tls-fingerprint']; + + if (proxy['underlying-proxy']) { + proxy['dialer-proxy'] = proxy['underlying-proxy']; + } + delete proxy['underlying-proxy']; + + if (isPresent(proxy, 'tls') && typeof proxy.tls !== 'boolean') { + delete proxy.tls; + } + delete proxy.subName; + delete proxy.collectionName; + delete proxy.id; + delete proxy.resolved; + delete proxy['no-resolve']; + if (type !== 'internal' || opts['delete-underscore-fields']) { + for (const key in proxy) { + if (proxy[key] == null || /^_/i.test(key)) { + delete proxy[key]; + } + } + } + if ( + ['grpc'].includes(proxy.network) && + proxy[`${proxy.network}-opts`] + ) { + delete proxy[`${proxy.network}-opts`]['_grpc-type']; + delete proxy[`${proxy.network}-opts`]['_grpc-authority']; + } + return proxy; + }); + + return type === 'internal' + ? list + : 'proxies:\n' + + list + .map((proxy) => ' - ' + JSON.stringify(proxy) + '\n') + .join(''); + }; + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/producers/egern.js b/backend/src/core/proxy-utils/producers/egern.js new file mode 100644 index 0000000000..80a3d93b3f --- /dev/null +++ b/backend/src/core/proxy-utils/producers/egern.js @@ -0,0 +1,403 @@ +import { isPresent } from './utils'; + +export default function Egern_Producer() { + const type = 'ALL'; + const produce = (proxies, type) => { + // https://egernapp.com/zh-CN/docs/configuration/proxies + const list = proxies + .filter((proxy) => { + // if (opts['include-unsupported-proxy']) return true; + if ( + ![ + 'http', + 'socks5', + 'ss', + 'trojan', + 'hysteria2', + 'vless', + 'vmess', + 'tuic', + ].includes(proxy.type) || + (proxy.type === 'ss' && + ((proxy.plugin === 'obfs' && + !['http', 'tls'].includes( + proxy['plugin-opts']?.mode, + )) || + ![ + 'chacha20-ietf-poly1305', + 'chacha20-poly1305', + 'aes-256-gcm', + 'aes-128-gcm', + 'none', + 'tbale', + 'rc4', + 'rc4-md5', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'bf-cfb', + 'camellia-128-cfb', + 'camellia-192-cfb', + 'camellia-256-cfb', + 'cast5-cfb', + 'des-cfb', + 'idea-cfb', + 'rc2-cfb', + 'seed-cfb', + 'salsa20', + 'chacha20', + 'chacha20-ietf', + '2022-blake3-aes-128-gcm', + '2022-blake3-aes-256-gcm', + ].includes(proxy.cipher))) || + (proxy.type === 'vmess' && + !['http', 'ws', 'tcp'].includes(proxy.network) && + proxy.network) || + (proxy.type === 'trojan' && + !['http', 'ws', 'tcp'].includes(proxy.network) && + proxy.network) || + (proxy.type === 'vless' && + (typeof proxy.flow !== 'undefined' || + proxy['reality-opts'] || + (!['http', 'ws', 'tcp'].includes(proxy.network) && + proxy.network))) || + (proxy.type === 'tuic' && + proxy.token && + proxy.token.length !== 0) + ) { + return false; + } + return true; + }) + .map((proxy) => { + const original = { ...proxy }; + if (proxy.tls && !proxy.sni) { + proxy.sni = proxy.server; + } + const prev_hop = + proxy.prev_hop || + proxy['underlying-proxy'] || + proxy['dialer-proxy'] || + proxy.detour; + + if (proxy.type === 'http') { + proxy = { + type: 'http', + name: proxy.name, + server: proxy.server, + port: proxy.port, + username: proxy.username, + password: proxy.password, + tfo: proxy.tfo || proxy['fast-open'], + next_hop: proxy.next_hop, + }; + } else if (proxy.type === 'socks5') { + proxy = { + type: 'socks5', + name: proxy.name, + server: proxy.server, + port: proxy.port, + username: proxy.username, + password: proxy.password, + tfo: proxy.tfo || proxy['fast-open'], + udp_relay: + proxy.udp || proxy.udp_relay || proxy.udp_relay, + next_hop: proxy.next_hop, + }; + } else if (proxy.type === 'ss') { + proxy = { + type: 'shadowsocks', + name: proxy.name, + method: + proxy.cipher === 'chacha20-ietf-poly1305' + ? 'chacha20-poly1305' + : proxy.cipher, + server: proxy.server, + port: proxy.port, + password: proxy.password, + tfo: proxy.tfo || proxy['fast-open'], + udp_relay: + proxy.udp || proxy.udp_relay || proxy.udp_relay, + next_hop: proxy.next_hop, + }; + if (original.plugin === 'obfs') { + proxy.obfs = original['plugin-opts'].mode; + proxy.obfs_host = original['plugin-opts'].host; + proxy.obfs_uri = original['plugin-opts'].path; + } + } else if (proxy.type === 'hysteria2') { + proxy = { + type: 'hysteria2', + name: proxy.name, + server: proxy.server, + port: proxy.port, + auth: proxy.password, + tfo: proxy.tfo || proxy['fast-open'], + udp_relay: + proxy.udp || proxy.udp_relay || proxy.udp_relay, + next_hop: proxy.next_hop, + sni: proxy.sni, + skip_tls_verify: proxy['skip-cert-verify'], + port_hopping: proxy.ports, + port_hopping_interval: proxy['hop-interval'], + }; + if ( + original['obfs-password'] && + original.obfs == 'salamander' + ) { + proxy.obfs = 'salamander'; + proxy.obfs_password = original['obfs-password']; + } + } else if (proxy.type === 'tuic') { + proxy = { + type: 'tuic', + name: proxy.name, + server: proxy.server, + port: proxy.port, + uuid: proxy.uuid, + password: proxy.password, + next_hop: proxy.next_hop, + sni: proxy.sni, + alpn: Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn || 'h3'], + skip_tls_verify: proxy['skip-cert-verify'], + port_hopping: proxy.ports, + port_hopping_interval: proxy['hop-interval'], + }; + } else if (proxy.type === 'trojan') { + if (proxy.network === 'ws') { + proxy.websocket = { + path: proxy['ws-opts']?.path, + host: proxy['ws-opts']?.headers?.Host, + }; + } + proxy = { + type: 'trojan', + name: proxy.name, + server: proxy.server, + port: proxy.port, + password: proxy.password, + tfo: proxy.tfo || proxy['fast-open'], + udp_relay: + proxy.udp || proxy.udp_relay || proxy.udp_relay, + next_hop: proxy.next_hop, + sni: proxy.sni, + skip_tls_verify: proxy['skip-cert-verify'], + websocket: proxy.websocket, + }; + } else if (proxy.type === 'vmess') { + // Egern:传输层,支持 ws/wss/http1/http2/tls,不配置则为 tcp + let security = proxy.cipher; + if ( + security && + ![ + 'auto', + 'none', + 'zero', + 'aes-128-gcm', + 'chacha20-poly1305', + ].includes(security) + ) { + security = 'auto'; + } + if (proxy.network === 'ws') { + proxy.transport = { + [proxy.tls ? 'wss' : 'ws']: { + path: proxy['ws-opts']?.path, + headers: { + Host: proxy['ws-opts']?.headers?.Host, + }, + sni: proxy.tls ? proxy.sni : undefined, + skip_tls_verify: proxy.tls + ? proxy['skip-cert-verify'] + : undefined, + }, + }; + } else if (proxy.network === 'http') { + proxy.transport = { + http1: { + method: proxy['http-opts']?.method, + path: Array.isArray(proxy['http-opts']?.path) + ? proxy['http-opts']?.path[0] + : proxy['http-opts']?.path, + headers: { + Host: Array.isArray( + proxy['http-opts']?.headers?.Host, + ) + ? proxy['http-opts']?.headers?.Host[0] + : proxy['http-opts']?.headers?.Host, + }, + skip_tls_verify: proxy['skip-cert-verify'], + }, + }; + } else if (proxy.network === 'h2') { + proxy.transport = { + http2: { + method: proxy['h2-opts']?.method, + path: Array.isArray(proxy['h2-opts']?.path) + ? proxy['h2-opts']?.path[0] + : proxy['h2-opts']?.path, + headers: { + Host: Array.isArray( + proxy['h2-opts']?.headers?.Host, + ) + ? proxy['h2-opts']?.headers?.Host[0] + : proxy['h2-opts']?.headers?.Host, + }, + skip_tls_verify: proxy['skip-cert-verify'], + }, + }; + } else if ( + (proxy.network === 'tcp' || !proxy.network) && + proxy.tls + ) { + proxy.transport = { + tls: { + sni: proxy.tls ? proxy.sni : undefined, + skip_tls_verify: proxy.tls + ? proxy['skip-cert-verify'] + : undefined, + }, + }; + } + proxy = { + type: 'vmess', + name: proxy.name, + server: proxy.server, + port: proxy.port, + user_id: proxy.uuid, + security, + tfo: proxy.tfo || proxy['fast-open'], + legacy: proxy.legacy, + udp_relay: + proxy.udp || proxy.udp_relay || proxy.udp_relay, + next_hop: proxy.next_hop, + transport: proxy.transport, + // sni: proxy.sni, + // skip_tls_verify: proxy['skip-cert-verify'], + }; + } else if (proxy.type === 'vless') { + if (proxy.network === 'ws') { + proxy.transport = { + [proxy.tls ? 'wss' : 'ws']: { + path: proxy['ws-opts']?.path, + headers: { + Host: proxy['ws-opts']?.headers?.Host, + }, + sni: proxy.tls ? proxy.sni : undefined, + skip_tls_verify: proxy.tls + ? proxy['skip-cert-verify'] + : undefined, + }, + }; + } else if (proxy.network === 'http') { + proxy.transport = { + http: { + method: proxy['http-opts']?.method, + path: Array.isArray(proxy['http-opts']?.path) + ? proxy['http-opts']?.path[0] + : proxy['http-opts']?.path, + headers: { + Host: Array.isArray( + proxy['http-opts']?.headers?.Host, + ) + ? proxy['http-opts']?.headers?.Host[0] + : proxy['http-opts']?.headers?.Host, + }, + skip_tls_verify: proxy['skip-cert-verify'], + }, + }; + } else if (proxy.network === 'tcp' || !proxy.network) { + proxy.transport = { + [proxy.tls ? 'tls' : 'tcp']: { + sni: proxy.tls ? proxy.sni : undefined, + skip_tls_verify: proxy.tls + ? proxy['skip-cert-verify'] + : undefined, + }, + }; + } + proxy = { + type: 'vless', + name: proxy.name, + server: proxy.server, + port: proxy.port, + user_id: proxy.uuid, + security: proxy.cipher, + tfo: proxy.tfo || proxy['fast-open'], + legacy: proxy.legacy, + udp_relay: + proxy.udp || proxy.udp_relay || proxy.udp_relay, + next_hop: proxy.next_hop, + transport: proxy.transport, + // sni: proxy.sni, + // skip_tls_verify: proxy['skip-cert-verify'], + }; + } + if ( + [ + 'http', + 'socks5', + 'ss', + 'trojan', + 'vless', + 'vmess', + ].includes(original.type) + ) { + if (isPresent(original, 'shadow-tls-password')) { + if (original['shadow-tls-version'] != 3) + throw new Error( + `shadow-tls version ${original['shadow-tls-version']} is not supported`, + ); + proxy.shadow_tls = { + password: original['shadow-tls-password'], + sni: original['shadow-tls-sni'], + }; + } else if ( + ['shadow-tls'].includes(original.plugin) && + original['plugin-opts'] + ) { + if (original['plugin-opts'].version != 3) + throw new Error( + `shadow-tls version ${original['plugin-opts'].version} is not supported`, + ); + proxy.shadow_tls = { + password: original['plugin-opts'].password, + sni: original['plugin-opts'].host, + }; + } + } + + delete proxy.subName; + delete proxy.collectionName; + delete proxy.id; + delete proxy.resolved; + delete proxy['no-resolve']; + if (type !== 'internal') { + for (const key in proxy) { + if (proxy[key] == null || /^_/i.test(key)) { + delete proxy[key]; + } + } + } + return { + [proxy.type]: { + ...proxy, + type: undefined, + prev_hop, + }, + }; + }); + return type === 'internal' + ? list + : 'proxies:\n' + + list + .map((proxy) => ' - ' + JSON.stringify(proxy) + '\n') + .join(''); + }; + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/producers/index.js b/backend/src/core/proxy-utils/producers/index.js new file mode 100644 index 0000000000..2915a77572 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/index.js @@ -0,0 +1,56 @@ +import Surge_Producer from './surge'; +import SurgeMac_Producer from './surgemac'; +import Clash_Producer from './clash'; +import ClashMeta_Producer from './clashmeta'; +import Stash_Producer from './stash'; +import Loon_Producer from './loon'; +import URI_Producer from './uri'; +import V2Ray_Producer from './v2ray'; +import QX_Producer from './qx'; +import Shadowrocket_Producer from './shadowrocket'; +import Surfboard_Producer from './surfboard'; +import singbox_Producer from './sing-box'; +import Egern_Producer from './egern'; + +function JSON_Producer() { + const type = 'ALL'; + const produce = (proxies, type) => + type === 'internal' ? proxies : JSON.stringify(proxies, null, 2); + return { type, produce }; +} + +export default { + qx: QX_Producer(), + QX: QX_Producer(), + QuantumultX: QX_Producer(), + surge: Surge_Producer(), + Surge: Surge_Producer(), + SurgeMac: SurgeMac_Producer(), + Loon: Loon_Producer(), + Clash: Clash_Producer(), + meta: ClashMeta_Producer(), + clashmeta: ClashMeta_Producer(), + 'clash.meta': ClashMeta_Producer(), + 'Clash.Meta': ClashMeta_Producer(), + ClashMeta: ClashMeta_Producer(), + mihomo: ClashMeta_Producer(), + Mihomo: ClashMeta_Producer(), + uri: URI_Producer(), + URI: URI_Producer(), + v2: V2Ray_Producer(), + v2ray: V2Ray_Producer(), + V2Ray: V2Ray_Producer(), + json: JSON_Producer(), + JSON: JSON_Producer(), + stash: Stash_Producer(), + Stash: Stash_Producer(), + shadowrocket: Shadowrocket_Producer(), + Shadowrocket: Shadowrocket_Producer(), + ShadowRocket: Shadowrocket_Producer(), + surfboard: Surfboard_Producer(), + Surfboard: Surfboard_Producer(), + singbox: singbox_Producer(), + 'sing-box': singbox_Producer(), + egern: Egern_Producer(), + Egern: Egern_Producer(), +}; diff --git a/backend/src/core/proxy-utils/producers/loon.js b/backend/src/core/proxy-utils/producers/loon.js new file mode 100644 index 0000000000..bcf9bf1ae0 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/loon.js @@ -0,0 +1,693 @@ +/* eslint-disable no-case-declarations */ +const targetPlatform = 'Loon'; +import { isPresent, Result } from './utils'; +import { isIPv4, isIPv6 } from '@/utils'; + +const ipVersions = { + dual: 'dual', + ipv4: 'v4-only', + ipv6: 'v6-only', + 'ipv4-prefer': 'prefer-v4', + 'ipv6-prefer': 'prefer-v6', +}; + +export default function Loon_Producer() { + const produce = (proxy, type, opts = {}) => { + switch (proxy.type) { + case 'ss': + return shadowsocks(proxy); + case 'ssr': + return shadowsocksr(proxy); + case 'trojan': + return trojan(proxy); + case 'vmess': + return vmess(proxy, opts['include-unsupported-proxy']); + case 'vless': + return vless(proxy, opts['include-unsupported-proxy']); + case 'http': + return http(proxy); + case 'socks5': + return socks5(proxy); + case 'wireguard': + return wireguard(proxy); + case 'hysteria2': + return hysteria2(proxy); + } + throw new Error( + `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`, + ); + }; + return { produce }; +} + +function shadowsocks(proxy) { + const result = new Result(proxy); + if ( + ![ + 'rc4', + 'rc4-md5', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'bf-cfb', + 'camellia-128-cfb', + 'camellia-192-cfb', + 'camellia-256-cfb', + 'salsa20', + 'chacha20', + 'chacha20-ietf', + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305', + '2022-blake3-aes-128-gcm', + '2022-blake3-aes-256-gcm', + ].includes(proxy.cipher) + ) { + throw new Error(`cipher ${proxy.cipher} is not supported`); + } + result.append( + `${proxy.name}=shadowsocks,${proxy.server},${proxy.port},${proxy.cipher},"${proxy.password}"`, + ); + + // obfs + if (isPresent(proxy, 'plugin')) { + if (proxy.plugin === 'obfs') { + result.append(`,obfs-name=${proxy['plugin-opts'].mode}`); + result.appendIfPresent( + `,obfs-host=${proxy['plugin-opts'].host}`, + 'plugin-opts.host', + ); + result.appendIfPresent( + `,obfs-uri=${proxy['plugin-opts'].path}`, + 'plugin-opts.path', + ); + } else if (!['shadow-tls'].includes(proxy.plugin)) { + throw new Error(`plugin ${proxy.plugin} is not supported`); + } + } + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + // udp-port + result.appendIfPresent(`,udp-port=${proxy['udp-port']}`, 'udp-port'); + } else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) { + const password = proxy['plugin-opts'].password; + const host = proxy['plugin-opts'].host; + const version = proxy['plugin-opts'].version; + if (password) { + result.append(`,shadow-tls-password=${password}`); + if (host) { + result.append(`,shadow-tls-sni=${host}`); + } + if (version) { + if (version < 2) { + throw new Error( + `shadow-tls version ${version} is not supported`, + ); + } + result.append(`,shadow-tls-version=${version}`); + } + // udp-port + result.appendIfPresent( + `,udp-port=${proxy['udp-port']}`, + 'udp-port', + ); + } + } + + // tfo + result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + // udp + if (proxy.udp) { + result.append(`,udp=true`); + } + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + + return result.toString(); +} + +function shadowsocksr(proxy) { + const result = new Result(proxy); + result.append( + `${proxy.name}=shadowsocksr,${proxy.server},${proxy.port},${proxy.cipher},"${proxy.password}"`, + ); + + // ssr protocol + result.append(`,protocol=${proxy.protocol}`); + result.appendIfPresent( + `,protocol-param=${proxy['protocol-param']}`, + 'protocol-param', + ); + + // obfs + result.appendIfPresent(`,obfs=${proxy.obfs}`, 'obfs'); + result.appendIfPresent(`,obfs-param=${proxy['obfs-param']}`, 'obfs-param'); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + // udp-port + result.appendIfPresent(`,udp-port=${proxy['udp-port']}`, 'udp-port'); + } else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) { + const password = proxy['plugin-opts'].password; + const host = proxy['plugin-opts'].host; + const version = proxy['plugin-opts'].version; + if (password) { + result.append(`,shadow-tls-password=${password}`); + if (host) { + result.append(`,shadow-tls-sni=${host}`); + } + if (version) { + if (version < 2) { + throw new Error( + `shadow-tls version ${version} is not supported`, + ); + } + result.append(`,shadow-tls-version=${version}`); + } + // udp-port + result.appendIfPresent( + `,udp-port=${proxy['udp-port']}`, + 'udp-port', + ); + } + } + + // tfo + result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + // udp + if (proxy.udp) { + result.append(`,udp=true`); + } + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + + return result.toString(); +} + +function trojan(proxy) { + const result = new Result(proxy); + result.append( + `${proxy.name}=trojan,${proxy.server},${proxy.port},"${proxy.password}"`, + ); + if (proxy.network === 'tcp') { + delete proxy.network; + } + // transport + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + result.append(`,transport=ws`); + result.appendIfPresent( + `,path=${proxy['ws-opts']?.path}`, + 'ws-opts.path', + ); + result.appendIfPresent( + `,host=${proxy['ws-opts']?.headers?.Host}`, + 'ws-opts.headers.Host', + ); + } else { + throw new Error(`network ${proxy.network} is unsupported`); + } + } + + // tls verification + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // sni + result.appendIfPresent(`,tls-name=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + result.appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + + // tfo + result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + // udp + if (proxy.udp) { + result.append(`,udp=true`); + } + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + + return result.toString(); +} + +function vmess(proxy) { + const isReality = !!proxy['reality-opts']; + + const result = new Result(proxy); + result.append( + `${proxy.name}=vmess,${proxy.server},${proxy.port},${proxy.cipher},"${proxy.uuid}"`, + ); + if (proxy.network === 'tcp') { + delete proxy.network; + } + // transport + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + result.append(`,transport=ws`); + result.appendIfPresent( + `,path=${proxy['ws-opts']?.path}`, + 'ws-opts.path', + ); + result.appendIfPresent( + `,host=${proxy['ws-opts']?.headers?.Host}`, + 'ws-opts.headers.Host', + ); + } else if (proxy.network === 'http') { + result.append(`,transport=http`); + let httpPath = proxy['http-opts']?.path; + let httpHost = proxy['http-opts']?.headers?.Host; + result.appendIfPresent( + `,path=${Array.isArray(httpPath) ? httpPath[0] : httpPath}`, + 'http-opts.path', + ); + result.appendIfPresent( + `,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`, + 'http-opts.headers.Host', + ); + } else { + throw new Error(`network ${proxy.network} is unsupported`); + } + } else { + result.append(`,transport=tcp`); + } + + // tls + result.appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); + + // tls verification + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + if (isReality) { + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,public-key="${proxy['reality-opts']['public-key']}"`, + 'reality-opts.public-key', + ); + result.appendIfPresent( + `,short-id=${proxy['reality-opts']['short-id']}`, + 'reality-opts.short-id', + ); + } else { + // sni + result.appendIfPresent(`,tls-name=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + result.appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + } + + // AEAD + if (isPresent(proxy, 'aead')) { + result.append(`,alterId=0`); + } else { + result.append(`,alterId=${proxy.alterId}`); + } + + // tfo + result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + // udp + if (proxy.udp) { + result.append(`,udp=true`); + } + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + return result.toString(); +} + +function vless(proxy) { + let isXtls = false; + const isReality = !!proxy['reality-opts']; + + if (typeof proxy.flow !== 'undefined') { + if (['xtls-rprx-vision'].includes(proxy.flow)) { + isXtls = true; + } else { + throw new Error(`VLESS flow(${proxy.flow}) is not supported`); + } + } + + const result = new Result(proxy); + result.append( + `${proxy.name}=vless,${proxy.server},${proxy.port},"${proxy.uuid}"`, + ); + if (proxy.network === 'tcp') { + delete proxy.network; + } + // transport + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + result.append(`,transport=ws`); + result.appendIfPresent( + `,path=${proxy['ws-opts']?.path}`, + 'ws-opts.path', + ); + result.appendIfPresent( + `,host=${proxy['ws-opts']?.headers?.Host}`, + 'ws-opts.headers.Host', + ); + } else if (proxy.network === 'http') { + result.append(`,transport=http`); + let httpPath = proxy['http-opts']?.path; + let httpHost = proxy['http-opts']?.headers?.Host; + result.appendIfPresent( + `,path=${Array.isArray(httpPath) ? httpPath[0] : httpPath}`, + 'http-opts.path', + ); + result.appendIfPresent( + `,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`, + 'http-opts.headers.Host', + ); + } else { + throw new Error(`network ${proxy.network} is unsupported`); + } + } else { + result.append(`,transport=tcp`); + } + + // tls + result.appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); + + // tls verification + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + if (isXtls) { + result.appendIfPresent(`,flow=${proxy.flow}`, 'flow'); + } + if (isReality) { + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,public-key="${proxy['reality-opts']['public-key']}"`, + 'reality-opts.public-key', + ); + result.appendIfPresent( + `,short-id=${proxy['reality-opts']['short-id']}`, + 'reality-opts.short-id', + ); + } else { + // sni + result.appendIfPresent(`,tls-name=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + result.appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + } + + // tfo + result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + // udp + if (proxy.udp) { + result.append(`,udp=true`); + } + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + return result.toString(); +} + +function http(proxy) { + const result = new Result(proxy); + const type = proxy.tls ? 'https' : 'http'; + result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,${proxy.username}`, 'username'); + result.appendIfPresent(`,"${proxy.password}"`, 'password'); + + // sni + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + + // tls verification + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + + return result.toString(); +} +function socks5(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=socks5,${proxy.server},${proxy.port}`); + result.appendIfPresent(`,${proxy.username}`, 'username'); + result.appendIfPresent(`,"${proxy.password}"`, 'password'); + + // tls + result.appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); + + // sni + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + + // tls verification + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + // udp + if (proxy.udp) { + result.append(`,udp=true`); + } + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + + return result.toString(); +} + +function wireguard(proxy) { + if (Array.isArray(proxy.peers) && proxy.peers.length > 0) { + proxy.server = proxy.peers[0].server; + proxy.port = proxy.peers[0].port; + proxy.ip = proxy.peers[0].ip; + proxy.ipv6 = proxy.peers[0].ipv6; + proxy['public-key'] = proxy.peers[0]['public-key']; + proxy['preshared-key'] = proxy.peers[0]['pre-shared-key']; + // https://github.com/MetaCubeX/mihomo/blob/0404e35be8736b695eae018a08debb175c1f96e6/docs/config.yaml#L717 + proxy['allowed-ips'] = proxy.peers[0]['allowed-ips']; + proxy.reserved = proxy.peers[0].reserved; + } + const result = new Result(proxy); + result.append(`${proxy.name}=wireguard`); + + result.appendIfPresent(`,interface-ip=${proxy.ip}`, 'ip'); + result.appendIfPresent(`,interface-ipv6=${proxy.ipv6}`, 'ipv6'); + + result.appendIfPresent( + `,private-key="${proxy['private-key']}"`, + 'private-key', + ); + result.appendIfPresent(`,mtu=${proxy.mtu}`, 'mtu'); + + if (proxy.dns) { + if (Array.isArray(proxy.dns)) { + proxy.dnsv6 = proxy.dns.find((i) => isIPv6(i)); + let dns = proxy.dns.find((i) => isIPv4(i)); + if (!dns) { + dns = proxy.dns.find((i) => !isIPv4(i) && !isIPv6(i)); + } + proxy.dns = dns; + } + } + result.appendIfPresent(`,dns=${proxy.dns}`, 'dns'); + result.appendIfPresent(`,dnsv6=${proxy.dnsv6}`, 'dnsv6'); + result.appendIfPresent( + `,keepalive=${proxy['persistent-keepalive']}`, + 'persistent-keepalive', + ); + result.appendIfPresent(`,keepalive=${proxy.keepalive}`, 'keepalive'); + const allowedIps = Array.isArray(proxy['allowed-ips']) + ? proxy['allowed-ips'].join(',') + : proxy['allowed-ips']; + let reserved = Array.isArray(proxy.reserved) + ? proxy.reserved.join(',') + : proxy.reserved; + if (reserved) { + reserved = `,reserved=[${reserved}]`; + } + let presharedKey = proxy['preshared-key'] ?? proxy['pre-shared-key']; + if (presharedKey) { + presharedKey = `,preshared-key="${presharedKey}"`; + } + result.append( + `,peers=[{public-key="${proxy['public-key']}",allowed-ips="${ + allowedIps ?? '0.0.0.0/0,::/0' + }",endpoint=${proxy.server}:${proxy.port}${reserved ?? ''}${ + presharedKey ?? '' + }}]`, + ); + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + return result.toString(); +} + +function hysteria2(proxy) { + if (proxy['obfs-password'] && proxy.obfs != 'salamander') { + throw new Error(`only salamander obfs is supported`); + } + const result = new Result(proxy); + result.append(`${proxy.name}=Hysteria2,${proxy.server},${proxy.port}`); + + result.appendIfPresent(`,"${proxy.password}"`, 'password'); + + // sni + result.appendIfPresent(`,tls-name=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + result.appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + if (proxy['obfs-password'] && proxy.obfs == 'salamander') { + result.append(`,salamander-password=${proxy['obfs-password']}`); + } + + // tfo + result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // block-quic + if (proxy['block-quic'] === 'on') { + result.append(',block-quic=true'); + } else if (proxy['block-quic'] === 'off') { + result.append(',block-quic=false'); + } + + // udp + if (proxy.udp) { + result.append(`,udp=true`); + } + + // download-bandwidth + result.appendIfPresent( + `,download-bandwidth=${`${proxy['down']}`.match(/\d+/)?.[0] || 0}`, + 'down', + ); + + result.appendIfPresent(`,ecn=${proxy.ecn}`, 'ecn'); + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version'); + + return result.toString(); +} diff --git a/backend/src/core/proxy-utils/producers/qx.js b/backend/src/core/proxy-utils/producers/qx.js new file mode 100644 index 0000000000..1e90f0cd25 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/qx.js @@ -0,0 +1,601 @@ +import { isPresent, Result } from './utils'; + +const targetPlatform = 'QX'; + +export default function QX_Producer() { + // eslint-disable-next-line no-unused-vars + const produce = (proxy, type, opts = {}) => { + switch (proxy.type) { + case 'ss': + return shadowsocks(proxy, opts['include-unsupported-proxy']); + case 'ssr': + return shadowsocksr(proxy); + case 'trojan': + return trojan(proxy); + case 'vmess': + return vmess(proxy); + case 'http': + return http(proxy); + case 'socks5': + return socks5(proxy); + case 'vless': + return vless(proxy); + } + throw new Error( + `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`, + ); + }; + return { produce }; +} + +function shadowsocks(proxy, includeUnsupportedProxy) { + const result = new Result(proxy); + const append = result.append.bind(result); + const appendIfPresent = result.appendIfPresent.bind(result); + if (!proxy.cipher) { + proxy.cipher = 'none'; + } + if ( + ![ + 'none', + 'rc4-md5', + 'rc4-md5-6', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'bf-cfb', + 'cast5-cfb', + 'des-cfb', + 'rc2-cfb', + 'salsa20', + 'chacha20', + 'chacha20-ietf', + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305', + ...(includeUnsupportedProxy + ? ['2022-blake3-aes-128-gcm', '2022-blake3-aes-256-gcm'] + : []), + ].includes(proxy.cipher) + ) { + throw new Error(`cipher ${proxy.cipher} is not supported`); + } + append(`shadowsocks=${proxy.server}:${proxy.port}`); + append(`,method=${proxy.cipher}`); + append(`,password=${proxy.password}`); + + // obfs + if (needTls(proxy)) { + proxy.tls = true; + } + if (isPresent(proxy, 'plugin')) { + if (proxy.plugin === 'obfs') { + const opts = proxy['plugin-opts']; + append(`,obfs=${opts.mode}`); + } else if ( + proxy.plugin === 'v2ray-plugin' && + proxy['plugin-opts'].mode === 'websocket' + ) { + const opts = proxy['plugin-opts']; + if (opts.tls) append(`,obfs=wss`); + else append(`,obfs=ws`); + } else { + throw new Error(`plugin is not supported`); + } + appendIfPresent( + `,obfs-host=${proxy['plugin-opts'].host}`, + 'plugin-opts.host', + ); + appendIfPresent( + `,obfs-uri=${proxy['plugin-opts'].path}`, + 'plugin-opts.path', + ); + } + + if (needTls(proxy)) { + appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn'); + appendIfPresent( + `,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`, + 'tls-no-session-ticket', + ); + appendIfPresent( + `,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`, + 'tls-no-session-reuse', + ); + // tls fingerprint + appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + appendIfPresent( + `,tls-verification=${!proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); + } + + // tfo + appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // udp + appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // udp over tcp + if (proxy['_ssr_python_uot']) { + append(`,udp-over-tcp=true`); + } else if (proxy['udp-over-tcp']) { + if ( + !proxy['udp-over-tcp-version'] || + proxy['udp-over-tcp-version'] === 1 + ) { + append(`,udp-over-tcp=sp.v1`); + } else if (proxy['udp-over-tcp-version'] === 2) { + append(`,udp-over-tcp=sp.v2`); + } + } + + // server_check_url + result.appendIfPresent( + `,server_check_url=${proxy['test-url']}`, + 'test-url', + ); + + // tag + append(`,tag=${proxy.name}`); + + return result.toString(); +} + +function shadowsocksr(proxy) { + const result = new Result(proxy); + const append = result.append.bind(result); + const appendIfPresent = result.appendIfPresent.bind(result); + + append(`shadowsocks=${proxy.server}:${proxy.port}`); + append(`,method=${proxy.cipher}`); + append(`,password=${proxy.password}`); + + // ssr protocol + append(`,ssr-protocol=${proxy.protocol}`); + appendIfPresent( + `,ssr-protocol-param=${proxy['protocol-param']}`, + 'protocol-param', + ); + + // obfs + appendIfPresent(`,obfs=${proxy.obfs}`, 'obfs'); + appendIfPresent(`,obfs-host=${proxy['obfs-param']}`, 'obfs-param'); + + // tfo + appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // udp + appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // server_check_url + result.appendIfPresent( + `,server_check_url=${proxy['test-url']}`, + 'test-url', + ); + + // tag + append(`,tag=${proxy.name}`); + + return result.toString(); +} + +function trojan(proxy) { + const result = new Result(proxy); + const append = result.append.bind(result); + const appendIfPresent = result.appendIfPresent.bind(result); + + append(`trojan=${proxy.server}:${proxy.port}`); + append(`,password=${proxy.password}`); + + // obfs ws + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + if (needTls(proxy)) append(`,obfs=wss`); + else append(`,obfs=ws`); + appendIfPresent( + `,obfs-uri=${proxy['ws-opts']?.path}`, + 'ws-opts.path', + ); + appendIfPresent( + `,obfs-host=${proxy['ws-opts']?.headers?.Host}`, + 'ws-opts.headers.Host', + ); + } else { + throw new Error(`network ${proxy.network} is unsupported`); + } + } + + // over tls + if (proxy.network !== 'ws' && needTls(proxy)) { + append(`,over-tls=true`); + } + + if (needTls(proxy)) { + appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn'); + appendIfPresent( + `,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`, + 'tls-no-session-ticket', + ); + appendIfPresent( + `,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`, + 'tls-no-session-reuse', + ); + // tls fingerprint + appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + appendIfPresent( + `,tls-verification=${!proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); + } + + // tfo + appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // udp + appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // server_check_url + result.appendIfPresent( + `,server_check_url=${proxy['test-url']}`, + 'test-url', + ); + + // tag + append(`,tag=${proxy.name}`); + + return result.toString(); +} + +function vmess(proxy) { + const result = new Result(proxy); + const append = result.append.bind(result); + const appendIfPresent = result.appendIfPresent.bind(result); + + append(`vmess=${proxy.server}:${proxy.port}`); + + // cipher + let cipher; + if (proxy.cipher === 'auto') { + cipher = 'chacha20-ietf-poly1305'; + } else { + cipher = proxy.cipher; + } + append(`,method=${cipher}`); + + append(`,password=${proxy.uuid}`); + + // obfs + if (needTls(proxy)) { + proxy.tls = true; + } + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + if (proxy.tls) append(`,obfs=wss`); + else append(`,obfs=ws`); + } else if (proxy.network === 'http') { + append(`,obfs=http`); + } else { + throw new Error(`network ${proxy.network} is unsupported`); + } + let transportPath = proxy[`${proxy.network}-opts`]?.path; + let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; + appendIfPresent( + `,obfs-uri=${ + Array.isArray(transportPath) ? transportPath[0] : transportPath + }`, + `${proxy.network}-opts.path`, + ); + appendIfPresent( + `,obfs-host=${ + Array.isArray(transportHost) ? transportHost[0] : transportHost + }`, + `${proxy.network}-opts.headers.Host`, + ); + } else { + // over-tls + if (proxy.tls) append(`,obfs=over-tls`); + } + + if (needTls(proxy)) { + appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn'); + appendIfPresent( + `,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`, + 'tls-no-session-ticket', + ); + appendIfPresent( + `,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`, + 'tls-no-session-reuse', + ); + // tls fingerprint + appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + appendIfPresent( + `,tls-verification=${!proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); + } + + // AEAD + if (isPresent(proxy, 'aead')) { + append(`,aead=${proxy.aead}`); + } else { + append(`,aead=${proxy.alterId === 0}`); + } + + // tfo + appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // udp + appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // server_check_url + result.appendIfPresent( + `,server_check_url=${proxy['test-url']}`, + 'test-url', + ); + + // tag + append(`,tag=${proxy.name}`); + + return result.toString(); +} +function vless(proxy) { + if (typeof proxy.flow !== 'undefined' || proxy['reality-opts']) { + throw new Error(`VLESS XTLS/REALITY is not supported`); + } + + const result = new Result(proxy); + const append = result.append.bind(result); + const appendIfPresent = result.appendIfPresent.bind(result); + + append(`vless=${proxy.server}:${proxy.port}`); + + // The method field for vless should be none. + let cipher = 'none'; + // if (proxy.cipher === 'auto') { + // cipher = 'chacha20-ietf-poly1305'; + // } else { + // cipher = proxy.cipher; + // } + append(`,method=${cipher}`); + + append(`,password=${proxy.uuid}`); + + // obfs + if (needTls(proxy)) { + proxy.tls = true; + } + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + if (proxy.tls) append(`,obfs=wss`); + else append(`,obfs=ws`); + } else if (proxy.network === 'http') { + append(`,obfs=http`); + } else if (!['tcp'].includes(proxy.network)) { + throw new Error(`network ${proxy.network} is unsupported`); + } + let transportPath = proxy[`${proxy.network}-opts`]?.path; + let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; + appendIfPresent( + `,obfs-uri=${ + Array.isArray(transportPath) ? transportPath[0] : transportPath + }`, + `${proxy.network}-opts.path`, + ); + appendIfPresent( + `,obfs-host=${ + Array.isArray(transportHost) ? transportHost[0] : transportHost + }`, + `${proxy.network}-opts.headers.Host`, + ); + } else { + // over-tls + if (proxy.tls) append(`,obfs=over-tls`); + } + + if (needTls(proxy)) { + appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn'); + appendIfPresent( + `,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`, + 'tls-no-session-ticket', + ); + appendIfPresent( + `,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`, + 'tls-no-session-reuse', + ); + // tls fingerprint + appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + appendIfPresent( + `,tls-verification=${!proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); + } + + // tfo + appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // udp + appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // server_check_url + result.appendIfPresent( + `,server_check_url=${proxy['test-url']}`, + 'test-url', + ); + + // tag + append(`,tag=${proxy.name}`); + + return result.toString(); +} + +function http(proxy) { + const result = new Result(proxy); + const append = result.append.bind(result); + const appendIfPresent = result.appendIfPresent.bind(result); + + append(`http=${proxy.server}:${proxy.port}`); + appendIfPresent(`,username=${proxy.username}`, 'username'); + appendIfPresent(`,password=${proxy.password}`, 'password'); + + // tls + if (needTls(proxy)) { + proxy.tls = true; + } + appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); + + if (needTls(proxy)) { + appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn'); + appendIfPresent( + `,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`, + 'tls-no-session-ticket', + ); + appendIfPresent( + `,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`, + 'tls-no-session-reuse', + ); + // tls fingerprint + appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + appendIfPresent( + `,tls-verification=${!proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); + } + + // tfo + appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // udp + appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // server_check_url + result.appendIfPresent( + `,server_check_url=${proxy['test-url']}`, + 'test-url', + ); + + // tag + append(`,tag=${proxy.name}`); + + return result.toString(); +} + +function socks5(proxy) { + const result = new Result(proxy); + const append = result.append.bind(result); + const appendIfPresent = result.appendIfPresent.bind(result); + + append(`socks5=${proxy.server}:${proxy.port}`); + appendIfPresent(`,username=${proxy.username}`, 'username'); + appendIfPresent(`,password=${proxy.password}`, 'password'); + + // tls + if (needTls(proxy)) { + proxy.tls = true; + } + appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); + + if (needTls(proxy)) { + appendIfPresent( + `,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`, + 'tls-pubkey-sha256', + ); + appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn'); + appendIfPresent( + `,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`, + 'tls-no-session-ticket', + ); + appendIfPresent( + `,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`, + 'tls-no-session-reuse', + ); + // tls fingerprint + appendIfPresent( + `,tls-cert-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + appendIfPresent( + `,tls-verification=${!proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); + } + + // tfo + appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); + + // udp + appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // server_check_url + result.appendIfPresent( + `,server_check_url=${proxy['test-url']}`, + 'test-url', + ); + + // tag + append(`,tag=${proxy.name}`); + + return result.toString(); +} + +function needTls(proxy) { + return proxy.tls; +} diff --git a/backend/src/core/proxy-utils/producers/shadowrocket.js b/backend/src/core/proxy-utils/producers/shadowrocket.js new file mode 100644 index 0000000000..a03fa71fb9 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/shadowrocket.js @@ -0,0 +1,237 @@ +import { isPresent } from '@/core/proxy-utils/producers/utils'; +import $ from '@/core/app'; + +export default function Shadowrocket_Producer() { + const type = 'ALL'; + const produce = (proxies, type, opts = {}) => { + const list = proxies + .filter((proxy) => { + if (opts['include-unsupported-proxy']) return true; + if (proxy.type === 'snell' && String(proxy.version) === '4') { + return false; + } else if (['mieru', 'anytls'].includes(proxy.type)) { + return false; + } else if (proxy['underlying-proxy'] || proxy['dialer-proxy']) { + $.error( + `Shadowrocket 不支持前置代理字段. 已过滤节点 ${proxy.name}. 请使用 App 内的 "代理通过" 功能`, + ); + return false; + } + return true; + }) + .map((proxy) => { + if (proxy.type === 'vmess') { + // handle vmess aead + if (isPresent(proxy, 'aead')) { + if (proxy.aead) { + proxy.alterId = 0; + } + delete proxy.aead; + } + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400 + // https://stash.wiki/proxy-protocols/proxy-types#vmess + if ( + isPresent(proxy, 'cipher') && + ![ + 'auto', + 'none', + 'zero', + 'aes-128-gcm', + 'chacha20-poly1305', + ].includes(proxy.cipher) + ) { + proxy.cipher = 'auto'; + } + } else if (proxy.type === 'tuic') { + if (isPresent(proxy, 'alpn')) { + proxy.alpn = Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn]; + } else { + proxy.alpn = ['h3']; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + } + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197 + if ( + (!proxy.token || proxy.token.length === 0) && + !isPresent(proxy, 'version') + ) { + proxy.version = 5; + } + } else if (proxy.type === 'hysteria') { + // auth_str 将会在未来某个时候删除 但是有的机场不规范 + if ( + isPresent(proxy, 'auth_str') && + !isPresent(proxy, 'auth-str') + ) { + proxy['auth-str'] = proxy['auth_str']; + } + if (isPresent(proxy, 'alpn')) { + proxy.alpn = Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn]; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + } + } else if (proxy.type === 'hysteria2') { + if (proxy['obfs-password'] && proxy.obfs == 'salamander') { + proxy.obfs = proxy['obfs-password']; + delete proxy['obfs-password']; + } + if (isPresent(proxy, 'alpn')) { + proxy.alpn = Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn]; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + } + } else if (proxy.type === 'wireguard') { + proxy.keepalive = + proxy.keepalive ?? proxy['persistent-keepalive']; + proxy['persistent-keepalive'] = proxy.keepalive; + proxy['preshared-key'] = + proxy['preshared-key'] ?? proxy['pre-shared-key']; + proxy['pre-shared-key'] = proxy['preshared-key']; + } else if (proxy.type === 'snell' && proxy.version < 3) { + delete proxy.udp; + } else if (proxy.type === 'vless') { + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + } else if (proxy.type === 'ss') { + if ( + isPresent(proxy, 'shadow-tls-password') && + !isPresent(proxy, 'plugin') + ) { + proxy.plugin = 'shadow-tls'; + proxy['plugin-opts'] = { + host: proxy['shadow-tls-sni'], + password: proxy['shadow-tls-password'], + version: proxy['shadow-tls-version'], + }; + delete proxy['shadow-tls-password']; + delete proxy['shadow-tls-sni']; + delete proxy['shadow-tls-version']; + } + } + + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'http' + ) { + let httpPath = proxy['http-opts']?.path; + if ( + isPresent(proxy, 'http-opts.path') && + !Array.isArray(httpPath) + ) { + proxy['http-opts'].path = [httpPath]; + } + let httpHost = proxy['http-opts']?.headers?.Host; + if ( + isPresent(proxy, 'http-opts.headers.Host') && + !Array.isArray(httpHost) + ) { + proxy['http-opts'].headers.Host = [httpHost]; + } + } + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } + if (proxy['plugin-opts']?.tls) { + if (isPresent(proxy, 'skip-cert-verify')) { + proxy['plugin-opts']['skip-cert-verify'] = + proxy['skip-cert-verify']; + } + } + if ( + [ + 'trojan', + 'tuic', + 'hysteria', + 'hysteria2', + 'juicity', + 'anytls', + ].includes(proxy.type) + ) { + delete proxy.tls; + } + + if (proxy['tls-fingerprint']) { + proxy.fingerprint = proxy['tls-fingerprint']; + } + delete proxy['tls-fingerprint']; + + if (proxy['underlying-proxy']) { + proxy['dialer-proxy'] = proxy['underlying-proxy']; + } + delete proxy['underlying-proxy']; + + if (isPresent(proxy, 'tls') && typeof proxy.tls !== 'boolean') { + delete proxy.tls; + } + delete proxy.subName; + delete proxy.collectionName; + delete proxy.id; + delete proxy.resolved; + delete proxy['no-resolve']; + if (type !== 'internal') { + for (const key in proxy) { + if (proxy[key] == null || /^_/i.test(key)) { + delete proxy[key]; + } + } + } + if ( + ['grpc'].includes(proxy.network) && + proxy[`${proxy.network}-opts`] + ) { + delete proxy[`${proxy.network}-opts`]['_grpc-type']; + delete proxy[`${proxy.network}-opts`]['_grpc-authority']; + } + return proxy; + }); + return type === 'internal' + ? list + : 'proxies:\n' + + list + .map((proxy) => { + return ' - ' + JSON.stringify(proxy) + '\n'; + }) + .join(''); + }; + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/producers/sing-box.js b/backend/src/core/proxy-utils/producers/sing-box.js new file mode 100644 index 0000000000..160cf92656 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/sing-box.js @@ -0,0 +1,890 @@ +import ClashMeta_Producer from './clashmeta'; +import $ from '@/core/app'; +import { isIPv4, isIPv6 } from '@/utils'; + +const detourParser = (proxy, parsedProxy) => { + parsedProxy.detour = proxy['dialer-proxy'] || proxy.detour; +}; +const networkParser = (proxy, parsedProxy) => { + if (['tcp', 'udp'].includes(proxy._network)) + parsedProxy.network = proxy._network; +}; +const tfoParser = (proxy, parsedProxy) => { + parsedProxy.tcp_fast_open = false; + if (proxy.tfo) parsedProxy.tcp_fast_open = true; + if (proxy.tcp_fast_open) parsedProxy.tcp_fast_open = true; + if (proxy['tcp-fast-open']) parsedProxy.tcp_fast_open = true; + if (!parsedProxy.tcp_fast_open) delete parsedProxy.tcp_fast_open; +}; + +const smuxParser = (smux, proxy) => { + if (!smux || !smux.enabled) return; + proxy.multiplex = { enabled: true }; + proxy.multiplex.protocol = smux.protocol; + if (smux['max-connections']) + proxy.multiplex.max_connections = parseInt( + `${smux['max-connections']}`, + 10, + ); + if (smux['max-streams']) + proxy.multiplex.max_streams = parseInt(`${smux['max-streams']}`, 10); + if (smux['min-streams']) + proxy.multiplex.min_streams = parseInt(`${smux['min-streams']}`, 10); + if (smux.padding) proxy.multiplex.padding = true; + if (smux['brutal-opts']?.up || smux['brutal-opts']?.down) { + proxy.multiplex.brutal = { + enabled: true, + }; + if (smux['brutal-opts']?.up) + proxy.multiplex.brutal.up_mbps = parseInt( + `${smux['brutal-opts']?.up}`, + 10, + ); + if (smux['brutal-opts']?.down) + proxy.multiplex.brutal.down_mbps = parseInt( + `${smux['brutal-opts']?.down}`, + 10, + ); + } +}; + +const wsParser = (proxy, parsedProxy) => { + const transport = { type: 'ws', headers: {} }; + if (proxy['ws-opts']) { + const { path: wsPath = '', headers: wsHeaders = {} } = proxy['ws-opts']; + if (wsPath !== '') transport.path = `${wsPath}`; + if (Object.keys(wsHeaders).length > 0) { + const headers = {}; + for (const key of Object.keys(wsHeaders)) { + let value = wsHeaders[key]; + if (value === '') continue; + if (!Array.isArray(value)) value = [`${value}`]; + if (value.length > 0) headers[key] = value; + } + const { Host: wsHost } = headers; + if (wsHost.length === 1) + for (const item of `Host:${wsHost[0]}`.split('\n')) { + const [key, value] = item.split(':'); + if (value.trim() === '') continue; + headers[key.trim()] = value.trim().split(','); + } + transport.headers = headers; + } + } + if (proxy['ws-headers']) { + const headers = {}; + for (const key of Object.keys(proxy['ws-headers'])) { + let value = proxy['ws-headers'][key]; + if (value === '') continue; + if (!Array.isArray(value)) value = [`${value}`]; + if (value.length > 0) headers[key] = value; + } + const { Host: wsHost } = headers; + if (wsHost.length === 1) + for (const item of `Host:${wsHost[0]}`.split('\n')) { + const [key, value] = item.split(':'); + if (value.trim() === '') continue; + headers[key.trim()] = value.trim().split(','); + } + for (const key of Object.keys(headers)) + transport.headers[key] = headers[key]; + } + if (proxy['ws-path'] && proxy['ws-path'] !== '') + transport.path = `${proxy['ws-path']}`; + if (transport.path) { + const reg = /^(.*?)(?:\?ed=(\d+))?$/; + // eslint-disable-next-line no-unused-vars + const [_, path = '', ed = ''] = reg.exec(transport.path); + transport.path = path; + if (ed !== '') { + transport.early_data_header_name = 'Sec-WebSocket-Protocol'; + transport.max_early_data = parseInt(ed, 10); + } + } + + if (parsedProxy.tls.insecure) + parsedProxy.tls.server_name = transport.headers.Host[0]; + if (proxy['ws-opts'] && proxy['ws-opts']['v2ray-http-upgrade']) { + transport.type = 'httpupgrade'; + if (transport.headers.Host) { + transport.host = transport.headers.Host[0]; + delete transport.headers.Host; + } + if (transport.max_early_data) delete transport.max_early_data; + if (transport.early_data_header_name) + delete transport.early_data_header_name; + } + for (const key of Object.keys(transport.headers)) { + const value = transport.headers[key]; + if (value.length === 1) transport.headers[key] = value[0]; + } + parsedProxy.transport = transport; +}; + +const h1Parser = (proxy, parsedProxy) => { + const transport = { type: 'http', headers: {} }; + if (proxy['http-opts']) { + const { + method = '', + path: h1Path = '', + headers: h1Headers = {}, + } = proxy['http-opts']; + if (method !== '') transport.method = method; + if (Array.isArray(h1Path)) { + transport.path = `${h1Path[0]}`; + } else if (h1Path !== '') transport.path = `${h1Path}`; + for (const key of Object.keys(h1Headers)) { + let value = h1Headers[key]; + if (value === '') continue; + if (key.toLowerCase() === 'host') { + let host = value; + if (!Array.isArray(host)) + host = `${host}`.split(',').map((i) => i.trim()); + if (host.length > 0) transport.host = host; + continue; + } + if (!Array.isArray(value)) + value = `${value}`.split(',').map((i) => i.trim()); + if (value.length > 0) transport.headers[key] = value; + } + } + if (proxy['http-host'] && proxy['http-host'] !== '') { + let host = proxy['http-host']; + if (!Array.isArray(host)) + host = `${host}`.split(',').map((i) => i.trim()); + if (host.length > 0) transport.host = host; + } + if (!transport.host) return; + if (proxy['http-path'] && proxy['http-path'] !== '') { + const path = proxy['http-path']; + if (Array.isArray(path)) { + transport.path = `${path[0]}`; + } else if (path !== '') transport.path = `${path}`; + } + if (parsedProxy.tls.insecure) + parsedProxy.tls.server_name = transport.host[0]; + if (transport.host.length === 1) transport.host = transport.host[0]; + for (const key of Object.keys(transport.headers)) { + const value = transport.headers[key]; + if (value.length === 1) transport.headers[key] = value[0]; + } + parsedProxy.transport = transport; +}; + +const h2Parser = (proxy, parsedProxy) => { + const transport = { type: 'http' }; + if (proxy['h2-opts']) { + let { host = '', path = '' } = proxy['h2-opts']; + if (path !== '') transport.path = `${path}`; + if (host !== '') { + if (!Array.isArray(host)) + host = `${host}`.split(',').map((i) => i.trim()); + if (host.length > 0) transport.host = host; + } + } + if (proxy['h2-host'] && proxy['h2-host'] !== '') { + let host = proxy['h2-host']; + if (!Array.isArray(host)) + host = `${host}`.split(',').map((i) => i.trim()); + if (host.length > 0) transport.host = host; + } + if (proxy['h2-path'] && proxy['h2-path'] !== '') + transport.path = `${proxy['h2-path']}`; + parsedProxy.tls.enabled = true; + if (parsedProxy.tls.insecure) + parsedProxy.tls.server_name = transport.host[0]; + if (transport.host.length === 1) transport.host = transport.host[0]; + parsedProxy.transport = transport; +}; + +const grpcParser = (proxy, parsedProxy) => { + const transport = { type: 'grpc' }; + if (proxy['grpc-opts']) { + const serviceName = proxy['grpc-opts']['grpc-service-name']; + if (serviceName != null && serviceName !== '') + transport.service_name = `${serviceName}`; + } + parsedProxy.transport = transport; +}; + +const tlsParser = (proxy, parsedProxy) => { + if (proxy.tls) parsedProxy.tls.enabled = true; + if (proxy.servername && proxy.servername !== '') + parsedProxy.tls.server_name = proxy.servername; + if (proxy.peer && proxy.peer !== '') + parsedProxy.tls.server_name = proxy.peer; + if (proxy.sni && proxy.sni !== '') parsedProxy.tls.server_name = proxy.sni; + if (proxy['skip-cert-verify']) parsedProxy.tls.insecure = true; + if (proxy.insecure) parsedProxy.tls.insecure = true; + if (proxy['disable-sni']) parsedProxy.tls.disable_sni = true; + if (typeof proxy.alpn === 'string') { + parsedProxy.tls.alpn = [proxy.alpn]; + } else if (Array.isArray(proxy.alpn)) parsedProxy.tls.alpn = proxy.alpn; + if (proxy.ca) parsedProxy.tls.certificate_path = `${proxy.ca}`; + if (proxy.ca_str) parsedProxy.tls.certificate = [proxy.ca_str]; + if (proxy['ca-str']) parsedProxy.tls.certificate = [proxy['ca-str']]; + if (proxy['reality-opts']) { + parsedProxy.tls.reality = { enabled: true }; + if (proxy['reality-opts']['public-key']) + parsedProxy.tls.reality.public_key = + proxy['reality-opts']['public-key']; + if (proxy['reality-opts']['short-id']) + parsedProxy.tls.reality.short_id = + proxy['reality-opts']['short-id']; + parsedProxy.tls.utls = { enabled: true }; + } + if ( + !['hysteria', 'hysteria2', 'tuic'].includes(proxy.type) && + proxy['client-fingerprint'] && + proxy['client-fingerprint'] !== '' + ) + parsedProxy.tls.utls = { + enabled: true, + fingerprint: proxy['client-fingerprint'], + }; + if (!parsedProxy.tls.enabled) delete parsedProxy.tls; +}; + +const sshParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'ssh', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy.username) parsedProxy.user = proxy.username; + if (proxy.password) parsedProxy.password = proxy.password; + // https://wiki.metacubex.one/config/proxies/ssh + // https://sing-box.sagernet.org/zh/configuration/outbound/ssh + if (proxy['privateKey']) parsedProxy.private_key_path = proxy['privateKey']; + if (proxy['private-key']) + parsedProxy.private_key_path = proxy['private-key']; + if (proxy['private-key-passphrase']) + parsedProxy.private_key_passphrase = proxy['private-key-passphrase']; + if (proxy['server-fingerprint']) { + parsedProxy.host_key = [proxy['server-fingerprint']]; + // https://manual.nssurge.com/policy/ssh.html + // Surge only supports curve25519-sha256 as the kex algorithm and aes128-gcm as the encryption algorithm. It means that the SSH server must use OpenSSH v7.3 or above. (It should not be a problem since OpenSSH 7.3 was released on 2016-08-01.) + // TODO: ? + parsedProxy.host_key_algorithms = [ + proxy['server-fingerprint'].split(' ')[0], + ]; + } + if (proxy['host-key']) parsedProxy.host_key = proxy['host-key']; + if (proxy['host-key-algorithms']) + parsedProxy.host_key_algorithms = proxy['host-key-algorithms']; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + return parsedProxy; +}; + +const httpParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'http', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + tls: { enabled: false, server_name: proxy.server, insecure: false }, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy.username) parsedProxy.username = proxy.username; + if (proxy.password) parsedProxy.password = proxy.password; + if (proxy.headers) { + parsedProxy.headers = {}; + for (const k of Object.keys(proxy.headers)) { + parsedProxy.headers[k] = `${proxy.headers[k]}`; + } + if (Object.keys(parsedProxy.headers).length === 0) + delete parsedProxy.headers; + } + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + tlsParser(proxy, parsedProxy); + return parsedProxy; +}; + +const socks5Parser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'socks', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + password: proxy.password, + version: '5', + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy.username) parsedProxy.username = proxy.username; + if (proxy.password) parsedProxy.password = proxy.password; + if (proxy.uot) parsedProxy.udp_over_tcp = true; + if (proxy['udp-over-tcp']) parsedProxy.udp_over_tcp = true; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + networkParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + return parsedProxy; +}; + +const shadowTLSParser = (proxy = {}) => { + const ssPart = { + tag: proxy.name, + type: 'shadowsocks', + method: proxy.cipher, + password: proxy.password, + detour: `${proxy.name}_shadowtls`, + }; + const stPart = { + tag: `${proxy.name}_shadowtls`, + type: 'shadowtls', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + version: proxy['plugin-opts'].version, + password: proxy['plugin-opts'].password, + tls: { + enabled: true, + server_name: proxy['plugin-opts'].host, + utls: { + enabled: true, + fingerprint: proxy['client-fingerprint'], + }, + }, + }; + if (stPart.server_port < 0 || stPart.server_port > 65535) + throw '端口值非法'; + if (proxy['fast-open'] === true) stPart.udp_fragment = true; + tfoParser(proxy, stPart); + detourParser(proxy, stPart); + smuxParser(proxy.smux, ssPart); + return { type: 'ss-with-st', ssPart, stPart }; +}; +const ssParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'shadowsocks', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + method: proxy.cipher, + password: proxy.password, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy.uot) parsedProxy.udp_over_tcp = true; + if (proxy['udp-over-tcp']) { + parsedProxy.udp_over_tcp = { + enabled: true, + version: + !proxy['udp-over-tcp-version'] || + proxy['udp-over-tcp-version'] === 1 + ? 1 + : 2, + }; + } + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + networkParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + if (proxy.plugin) { + const optArr = []; + if (proxy.plugin === 'obfs') { + parsedProxy.plugin = 'obfs-local'; + parsedProxy.plugin_opts = ''; + if (proxy['obfs-host']) + proxy['plugin-opts'].host = proxy['obfs-host']; + Object.keys(proxy['plugin-opts']).forEach((k) => { + switch (k) { + case 'mode': + optArr.push(`obfs=${proxy['plugin-opts'].mode}`); + break; + case 'host': + optArr.push(`obfs-host=${proxy['plugin-opts'].host}`); + break; + default: + optArr.push(`${k}=${proxy['plugin-opts'][k]}`); + break; + } + }); + } + if (proxy.plugin === 'v2ray-plugin') { + parsedProxy.plugin = 'v2ray-plugin'; + if (proxy['ws-host']) proxy['plugin-opts'].host = proxy['ws-host']; + if (proxy['ws-path']) proxy['plugin-opts'].path = proxy['ws-path']; + Object.keys(proxy['plugin-opts']).forEach((k) => { + switch (k) { + case 'tls': + if (proxy['plugin-opts'].tls) optArr.push('tls'); + break; + case 'host': + optArr.push(`host=${proxy['plugin-opts'].host}`); + break; + case 'path': + optArr.push(`path=${proxy['plugin-opts'].path}`); + break; + case 'headers': + optArr.push( + `headers=${JSON.stringify( + proxy['plugin-opts'].headers, + )}`, + ); + break; + case 'mux': + if (proxy['plugin-opts'].mux) + parsedProxy.multiplex = { enabled: true }; + break; + default: + optArr.push(`${k}=${proxy['plugin-opts'][k]}`); + } + }); + } + parsedProxy.plugin_opts = optArr.join(';'); + } + + return parsedProxy; +}; +// eslint-disable-next-line no-unused-vars +const ssrParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'shadowsocksr', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + method: proxy.cipher, + password: proxy.password, + obfs: proxy.obfs, + protocol: proxy.protocol, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy['obfs-param']) parsedProxy.obfs_param = proxy['obfs-param']; + if (proxy['protocol-param'] && proxy['protocol-param'] !== '') + parsedProxy.protocol_param = proxy['protocol-param']; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + return parsedProxy; +}; + +const vmessParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'vmess', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + uuid: proxy.uuid, + security: proxy.cipher, + alter_id: parseInt(`${proxy.alterId}`, 10), + tls: { enabled: false, server_name: proxy.server, insecure: false }, + }; + if ( + [ + 'auto', + 'none', + 'zero', + 'aes-128-gcm', + 'chacha20-poly1305', + 'aes-128-ctr', + ].indexOf(parsedProxy.security) === -1 + ) + parsedProxy.security = 'auto'; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy.xudp) parsedProxy.packet_encoding = 'xudp'; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + if (proxy.network === 'ws') wsParser(proxy, parsedProxy); + if (proxy.network === 'h2') h2Parser(proxy, parsedProxy); + if (proxy.network === 'http') h1Parser(proxy, parsedProxy); + if (proxy.network === 'grpc') grpcParser(proxy, parsedProxy); + networkParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + tlsParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + return parsedProxy; +}; + +const vlessParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'vless', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + uuid: proxy.uuid, + tls: { enabled: false, server_name: proxy.server, insecure: false }, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + if (proxy.flow === 'xtls-rprx-vision') parsedProxy.flow = proxy.flow; + if (proxy.network === 'ws') wsParser(proxy, parsedProxy); + if (proxy.network === 'grpc') grpcParser(proxy, parsedProxy); + networkParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + tlsParser(proxy, parsedProxy); + return parsedProxy; +}; +const trojanParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'trojan', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + password: proxy.password, + tls: { enabled: true, server_name: proxy.server, insecure: false }, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + if (proxy.network === 'grpc') grpcParser(proxy, parsedProxy); + if (proxy.network === 'ws') wsParser(proxy, parsedProxy); + networkParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + tlsParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + return parsedProxy; +}; +const hysteriaParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'hysteria', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + disable_mtu_discovery: false, + tls: { enabled: true, server_name: proxy.server, insecure: false }, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy.auth_str) parsedProxy.auth_str = `${proxy.auth_str}`; + if (proxy['auth-str']) parsedProxy.auth_str = `${proxy['auth-str']}`; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + // eslint-disable-next-line no-control-regex + const reg = new RegExp('^[0-9]+[ \t]*[KMGT]*[Bb]ps$'); + if (reg.test(`${proxy.up}`)) { + parsedProxy.up = `${proxy.up}`; + } else { + parsedProxy.up_mbps = parseInt(`${proxy.up}`, 10); + } + if (reg.test(`${proxy.down}`)) { + parsedProxy.down = `${proxy.down}`; + } else { + parsedProxy.down_mbps = parseInt(`${proxy.down}`, 10); + } + if (proxy.obfs) parsedProxy.obfs = proxy.obfs; + if (proxy.recv_window_conn) + parsedProxy.recv_window_conn = proxy.recv_window_conn; + if (proxy['recv-window-conn']) + parsedProxy.recv_window_conn = proxy['recv-window-conn']; + if (proxy.recv_window) parsedProxy.recv_window = proxy.recv_window; + if (proxy['recv-window']) parsedProxy.recv_window = proxy['recv-window']; + if (proxy.disable_mtu_discovery) { + if (typeof proxy.disable_mtu_discovery === 'boolean') { + parsedProxy.disable_mtu_discovery = proxy.disable_mtu_discovery; + } else { + if (proxy.disable_mtu_discovery === 1) + parsedProxy.disable_mtu_discovery = true; + } + } + networkParser(proxy, parsedProxy); + tlsParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + return parsedProxy; +}; +const hysteria2Parser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'hysteria2', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + password: proxy.password, + obfs: {}, + tls: { enabled: true, server_name: proxy.server, insecure: false }, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy['hop-interval']) + parsedProxy.hop_interval = /^\d+$/.test(proxy['hop-interval']) + ? `${proxy['hop-interval']}s` + : proxy['hop-interval']; + if (proxy['ports']) + parsedProxy.server_ports = proxy['ports'] + .split(/\s*,\s*/) + .map((p) => p.replace(/\s*-\s*/g, ':')); + if (proxy.up) parsedProxy.up_mbps = parseInt(`${proxy.up}`, 10); + if (proxy.down) parsedProxy.down_mbps = parseInt(`${proxy.down}`, 10); + if (proxy.obfs === 'salamander') parsedProxy.obfs.type = 'salamander'; + if (proxy['obfs-password']) + parsedProxy.obfs.password = proxy['obfs-password']; + if (!parsedProxy.obfs.type) delete parsedProxy.obfs; + networkParser(proxy, parsedProxy); + tlsParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + return parsedProxy; +}; +const tuic5Parser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'tuic', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + uuid: proxy.uuid, + password: proxy.password, + tls: { enabled: true, server_name: proxy.server, insecure: false }, + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + if ( + proxy['congestion-controller'] && + proxy['congestion-controller'] !== 'cubic' + ) + parsedProxy.congestion_control = proxy['congestion-controller']; + if (proxy['udp-relay-mode'] && proxy['udp-relay-mode'] !== 'native') + parsedProxy.udp_relay_mode = proxy['udp-relay-mode']; + if (proxy['reduce-rtt']) parsedProxy.zero_rtt_handshake = true; + if (proxy['udp-over-stream']) parsedProxy.udp_over_stream = true; + if (proxy['heartbeat-interval']) + parsedProxy.heartbeat = `${proxy['heartbeat-interval']}ms`; + networkParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + tlsParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + return parsedProxy; +}; +const anytlsParser = (proxy = {}) => { + const parsedProxy = { + tag: proxy.name, + type: 'anytls', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + password: proxy.password, + tls: { enabled: true, server_name: proxy.server, insecure: false }, + }; + if (/^\d+$/.test(proxy['idle-session-check-interval'])) + parsedProxy.idle_session_check_interval = `${proxy['idle-session-check-interval']}s`; + if (/^\d+$/.test(proxy['idle-session-timeout'])) + parsedProxy.idle_session_timeout = `${proxy['idle-session-timeout']}s`; + detourParser(proxy, parsedProxy); + tlsParser(proxy, parsedProxy); + return parsedProxy; +}; + +const wireguardParser = (proxy = {}) => { + const local_address = ['ip', 'ipv6'] + .map((i) => proxy[i]) + .map((i) => { + if (isIPv4(i)) return `${i}/32`; + if (isIPv6(i)) return `${i}/128`; + }) + .filter((i) => i); + const parsedProxy = { + tag: proxy.name, + type: 'wireguard', + server: proxy.server, + server_port: parseInt(`${proxy.port}`, 10), + local_address, + private_key: proxy['private-key'], + peer_public_key: proxy['public-key'], + pre_shared_key: proxy['pre-shared-key'], + reserved: [], + }; + if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) + throw 'invalid port'; + if (proxy['fast-open']) parsedProxy.udp_fragment = true; + if (typeof proxy.reserved === 'string') { + parsedProxy.reserved = proxy.reserved; + } else if (Array.isArray(proxy.reserved)) { + for (const r of proxy.reserved) parsedProxy.reserved.push(r); + } else { + delete parsedProxy.reserved; + } + if (proxy.peers && proxy.peers.length > 0) { + parsedProxy.peers = []; + for (const p of proxy.peers) { + const peer = { + server: p.server, + server_port: parseInt(`${p.port}`, 10), + public_key: p['public-key'], + allowed_ips: p['allowed-ips'] || p.allowed_ips, + reserved: [], + }; + if (typeof p.reserved === 'string') { + peer.reserved.push(p.reserved); + } else if (Array.isArray(p.reserved)) { + for (const r of p.reserved) peer.reserved.push(r); + } else { + delete peer.reserved; + } + if (p['pre-shared-key']) peer.pre_shared_key = p['pre-shared-key']; + parsedProxy.peers.push(peer); + } + } + networkParser(proxy, parsedProxy); + tfoParser(proxy, parsedProxy); + detourParser(proxy, parsedProxy); + smuxParser(proxy.smux, parsedProxy); + return parsedProxy; +}; + +export default function singbox_Producer() { + const type = 'ALL'; + const produce = (proxies, type, opts = {}) => { + const list = []; + ClashMeta_Producer() + .produce(proxies, 'internal', { 'include-unsupported-proxy': true }) + .map((proxy) => { + try { + switch (proxy.type) { + case 'ssh': + list.push(sshParser(proxy)); + break; + case 'http': + list.push(httpParser(proxy)); + break; + case 'socks5': + if (proxy.tls) { + throw new Error( + `Platform sing-box does not support proxy type: ${proxy.type} with tls`, + ); + } else { + list.push(socks5Parser(proxy)); + } + break; + case 'ss': + // if (!proxy.cipher) { + // proxy.cipher = 'none'; + // } + // if ( + // ![ + // '2022-blake3-aes-128-gcm', + // '2022-blake3-aes-256-gcm', + // '2022-blake3-chacha20-poly1305', + // 'aes-128-cfb', + // 'aes-128-ctr', + // 'aes-128-gcm', + // 'aes-192-cfb', + // 'aes-192-ctr', + // 'aes-192-gcm', + // 'aes-256-cfb', + // 'aes-256-ctr', + // 'aes-256-gcm', + // 'chacha20-ietf', + // 'chacha20-ietf-poly1305', + // 'none', + // 'rc4-md5', + // 'xchacha20', + // 'xchacha20-ietf-poly1305', + // ].includes(proxy.cipher) + // ) { + // throw new Error( + // `cipher ${proxy.cipher} is not supported`, + // ); + // } + if (proxy.plugin === 'shadow-tls') { + const { ssPart, stPart } = + shadowTLSParser(proxy); + list.push(ssPart); + list.push(stPart); + } else { + list.push(ssParser(proxy)); + } + break; + case 'ssr': + if (opts['include-unsupported-proxy']) { + list.push(ssrParser(proxy)); + } else { + throw new Error( + `Platform sing-box does not support proxy type: ${proxy.type}`, + ); + } + break; + case 'vmess': + if ( + !proxy.network || + ['ws', 'grpc', 'h2', 'http'].includes( + proxy.network, + ) + ) { + list.push(vmessParser(proxy)); + } else { + throw new Error( + `Platform sing-box does not support proxy type: ${proxy.type} with network ${proxy.network}`, + ); + } + break; + case 'vless': + if ( + !proxy.flow || + ['xtls-rprx-vision'].includes(proxy.flow) + ) { + list.push(vlessParser(proxy)); + } else { + throw new Error( + `Platform sing-box does not support proxy type: ${proxy.type} with flow ${proxy.flow}`, + ); + } + break; + case 'trojan': + if (!proxy.flow) { + list.push(trojanParser(proxy)); + } else { + throw new Error( + `Platform sing-box does not support proxy type: ${proxy.type} with flow ${proxy.flow}`, + ); + } + break; + case 'hysteria': + list.push(hysteriaParser(proxy)); + break; + case 'hysteria2': + list.push( + hysteria2Parser( + proxy, + opts['include-unsupported-proxy'], + ), + ); + break; + case 'tuic': + if (!proxy.token || proxy.token.length === 0) { + list.push(tuic5Parser(proxy)); + } else { + throw new Error( + `Platform sing-box does not support proxy type: TUIC v4`, + ); + } + break; + case 'wireguard': + list.push(wireguardParser(proxy)); + break; + case 'anytls': + list.push(anytlsParser(proxy)); + break; + default: + throw new Error( + `Platform sing-box does not support proxy type: ${proxy.type}`, + ); + } + } catch (e) { + // console.log(e); + $.error(e.message ?? e); + } + }); + + return type === 'internal' + ? list + : JSON.stringify({ outbounds: list }, null, 2); + }; + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/producers/stash.js b/backend/src/core/proxy-utils/producers/stash.js new file mode 100644 index 0000000000..7658370d12 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/stash.js @@ -0,0 +1,308 @@ +import { isPresent } from '@/core/proxy-utils/producers/utils'; +import $ from '@/core/app'; + +export default function Stash_Producer() { + const type = 'ALL'; + const produce = (proxies, type, opts = {}) => { + // https://stash.wiki/proxy-protocols/proxy-types#shadowsocks + const list = proxies + .filter((proxy) => { + if ( + ![ + 'ss', + 'ssr', + 'vmess', + 'socks5', + 'http', + 'snell', + 'trojan', + 'tuic', + 'vless', + 'wireguard', + 'hysteria', + 'hysteria2', + 'ssh', + 'juicity', + ].includes(proxy.type) || + (proxy.type === 'ss' && + ![ + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'rc4-md5', + 'chacha20-ietf', + 'xchacha20', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305', + '2022-blake3-aes-128-gcm', + '2022-blake3-aes-256-gcm', + ].includes(proxy.cipher)) || + (proxy.type === 'snell' && String(proxy.version) === '4') || + (opts['include-unsupported-proxy'] + ? proxy.type === 'vless' && + proxy['reality-opts'] && + !['xtls-rprx-vision'].includes(proxy.flow) + : proxy.type === 'vless' && proxy['reality-opts']) + ) { + return false; + } else if (proxy['underlying-proxy'] || proxy['dialer-proxy']) { + $.error( + `Stash 暂不支持前置代理字段. 已过滤节点 ${proxy.name}. 请使用 代理的转发链 https://stash.wiki/proxy-protocols/proxy-groups#relay`, + ); + return false; + } + return true; + }) + .map((proxy) => { + if (proxy.type === 'vmess') { + // handle vmess aead + if (isPresent(proxy, 'aead')) { + if (proxy.aead) { + proxy.alterId = 0; + } + delete proxy.aead; + } + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400 + // https://stash.wiki/proxy-protocols/proxy-types#vmess + if ( + isPresent(proxy, 'cipher') && + ![ + 'auto', + 'aes-128-gcm', + 'chacha20-poly1305', + 'none', + ].includes(proxy.cipher) + ) { + proxy.cipher = 'auto'; + } + } else if (proxy.type === 'tuic') { + if (isPresent(proxy, 'alpn')) { + proxy.alpn = Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn]; + } else { + proxy.alpn = ['h3']; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + delete proxy.tfo; + } + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197 + if ( + (!proxy.token || proxy.token.length === 0) && + !isPresent(proxy, 'version') + ) { + proxy.version = 5; + } + } else if (proxy.type === 'hysteria') { + // auth_str 将会在未来某个时候删除 但是有的机场不规范 + if ( + isPresent(proxy, 'auth_str') && + !isPresent(proxy, 'auth-str') + ) { + proxy['auth-str'] = proxy['auth_str']; + } + if (isPresent(proxy, 'alpn')) { + proxy.alpn = Array.isArray(proxy.alpn) + ? proxy.alpn + : [proxy.alpn]; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + delete proxy.tfo; + } + if ( + isPresent(proxy, 'down') && + !isPresent(proxy, 'down-speed') + ) { + proxy['down-speed'] = proxy.down; + delete proxy.down; + } + if ( + isPresent(proxy, 'up') && + !isPresent(proxy, 'up-speed') + ) { + proxy['up-speed'] = proxy.up; + delete proxy.up; + } + if (isPresent(proxy, 'down-speed')) { + proxy['down-speed'] = + `${proxy['down-speed']}`.match(/\d+/)?.[0] || 0; + } + if (isPresent(proxy, 'up-speed')) { + proxy['up-speed'] = + `${proxy['up-speed']}`.match(/\d+/)?.[0] || 0; + } + } else if (proxy.type === 'hysteria2') { + if ( + isPresent(proxy, 'password') && + !isPresent(proxy, 'auth') + ) { + proxy.auth = proxy.password; + delete proxy.password; + } + if ( + isPresent(proxy, 'tfo') && + !isPresent(proxy, 'fast-open') + ) { + proxy['fast-open'] = proxy.tfo; + delete proxy.tfo; + } + if ( + isPresent(proxy, 'down') && + !isPresent(proxy, 'down-speed') + ) { + proxy['down-speed'] = proxy.down; + delete proxy.down; + } + if ( + isPresent(proxy, 'up') && + !isPresent(proxy, 'up-speed') + ) { + proxy['up-speed'] = proxy.up; + delete proxy.up; + } + if (isPresent(proxy, 'down-speed')) { + proxy['down-speed'] = + `${proxy['down-speed']}`.match(/\d+/)?.[0] || 0; + } + if (isPresent(proxy, 'up-speed')) { + proxy['up-speed'] = + `${proxy['up-speed']}`.match(/\d+/)?.[0] || 0; + } + } else if (proxy.type === 'wireguard') { + proxy.keepalive = + proxy.keepalive ?? proxy['persistent-keepalive']; + proxy['persistent-keepalive'] = proxy.keepalive; + proxy['preshared-key'] = + proxy['preshared-key'] ?? proxy['pre-shared-key']; + proxy['pre-shared-key'] = proxy['preshared-key']; + } else if (proxy.type === 'snell' && proxy.version < 3) { + delete proxy.udp; + } else if (proxy.type === 'vless') { + if (isPresent(proxy, 'sni')) { + proxy.servername = proxy.sni; + delete proxy.sni; + } + } + + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'http' + ) { + let httpPath = proxy['http-opts']?.path; + if ( + isPresent(proxy, 'http-opts.path') && + !Array.isArray(httpPath) + ) { + proxy['http-opts'].path = [httpPath]; + } + let httpHost = proxy['http-opts']?.headers?.Host; + if ( + isPresent(proxy, 'http-opts.headers.Host') && + !Array.isArray(httpHost) + ) { + proxy['http-opts'].headers.Host = [httpHost]; + } + } + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } + if (proxy['plugin-opts']?.tls) { + if (isPresent(proxy, 'skip-cert-verify')) { + proxy['plugin-opts']['skip-cert-verify'] = + proxy['skip-cert-verify']; + } + } + if ( + [ + 'trojan', + 'tuic', + 'hysteria', + 'hysteria2', + 'juicity', + 'anytls', + ].includes(proxy.type) + ) { + delete proxy.tls; + } + if (proxy['tls-fingerprint']) { + proxy['server-cert-fingerprint'] = proxy['tls-fingerprint']; + } + delete proxy['tls-fingerprint']; + + if (isPresent(proxy, 'tls') && typeof proxy.tls !== 'boolean') { + delete proxy.tls; + } + + if (proxy['test-url']) { + proxy['benchmark-url'] = proxy['test-url']; + delete proxy['test-url']; + } + if (proxy['test-timeout']) { + proxy['benchmark-timeout'] = proxy['test-timeout']; + delete proxy['test-timeout']; + } + + delete proxy.subName; + delete proxy.collectionName; + delete proxy.id; + delete proxy.resolved; + delete proxy['no-resolve']; + if (type !== 'internal') { + for (const key in proxy) { + if (proxy[key] == null || /^_/i.test(key)) { + delete proxy[key]; + } + } + } + if ( + ['grpc'].includes(proxy.network) && + proxy[`${proxy.network}-opts`] + ) { + delete proxy[`${proxy.network}-opts`]['_grpc-type']; + delete proxy[`${proxy.network}-opts`]['_grpc-authority']; + } + return proxy; + }); + return type === 'internal' + ? list + : 'proxies:\n' + + list + .map((proxy) => ' - ' + JSON.stringify(proxy) + '\n') + .join(''); + }; + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/producers/surfboard.js b/backend/src/core/proxy-utils/producers/surfboard.js new file mode 100644 index 0000000000..02c5ad1114 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/surfboard.js @@ -0,0 +1,226 @@ +import { Result, isPresent } from './utils'; +import { isNotBlank } from '@/utils'; +// import $ from '@/core/app'; + +const targetPlatform = 'Surfboard'; + +export default function Surfboard_Producer() { + const produce = (proxy) => { + proxy.name = proxy.name.replace(/=|,/g, ''); + switch (proxy.type) { + case 'ss': + return shadowsocks(proxy); + case 'trojan': + return trojan(proxy); + case 'vmess': + return vmess(proxy); + case 'http': + return http(proxy); + case 'socks5': + return socks5(proxy); + case 'wireguard-surge': + return wireguard(proxy); + } + throw new Error( + `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`, + ); + }; + return { produce }; +} + +function shadowsocks(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`); + if ( + ![ + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305', + 'rc4', + 'rc4-md5', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'bf-cfb', + 'camellia-128-cfb', + 'camellia-192-cfb', + 'camellia-256-cfb', + 'salsa20', + 'chacha20', + 'chacha20-ietf', + ].includes(proxy.cipher) + ) { + throw new Error(`cipher ${proxy.cipher} is not supported`); + } + result.append(`,encrypt-method=${proxy.cipher}`); + result.appendIfPresent(`,password=${proxy.password}`, 'password'); + + // obfs + if (isPresent(proxy, 'plugin')) { + if (proxy.plugin === 'obfs') { + result.append(`,obfs=${proxy['plugin-opts'].mode}`); + result.appendIfPresent( + `,obfs-host=${proxy['plugin-opts'].host}`, + 'plugin-opts.host', + ); + result.appendIfPresent( + `,obfs-uri=${proxy['plugin-opts'].path}`, + 'plugin-opts.path', + ); + } else { + throw new Error(`plugin ${proxy.plugin} is not supported`); + } + } + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + return result.toString(); +} + +function trojan(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,password=${proxy.password}`, 'password'); + + // transport + handleTransport(result, proxy); + + // tls + result.appendIfPresent(`,tls=${proxy.tls}`, 'tls'); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + return result.toString(); +} + +function vmess(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,username=${proxy.uuid}`, 'uuid'); + + // transport + handleTransport(result, proxy); + + // AEAD + if (isPresent(proxy, 'aead')) { + result.append(`,vmess-aead=${proxy.aead}`); + } else { + result.append(`,vmess-aead=${proxy.alterId === 0}`); + } + + // tls + result.appendIfPresent(`,tls=${proxy.tls}`, 'tls'); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + return result.toString(); +} + +function http(proxy) { + const result = new Result(proxy); + const type = proxy.tls ? 'https' : 'http'; + result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,${proxy.username}`, 'username'); + result.appendIfPresent(`,${proxy.password}`, 'password'); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + return result.toString(); +} + +function socks5(proxy) { + const result = new Result(proxy); + const type = proxy.tls ? 'socks5-tls' : 'socks5'; + result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,${proxy.username}`, 'username'); + result.appendIfPresent(`,${proxy.password}`, 'password'); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + return result.toString(); +} + +function wireguard(proxy) { + const result = new Result(proxy); + + result.append(`${proxy.name}=wireguard`); + + result.appendIfPresent( + `,section-name=${proxy['section-name']}`, + 'section-name', + ); + + return result.toString(); +} + +function handleTransport(result, proxy) { + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + result.append(`,ws=true`); + if (isPresent(proxy, 'ws-opts')) { + result.appendIfPresent( + `,ws-path=${proxy['ws-opts'].path}`, + 'ws-opts.path', + ); + if (isPresent(proxy, 'ws-opts.headers')) { + const headers = proxy['ws-opts'].headers; + const value = Object.keys(headers) + .map((k) => { + let v = headers[k]; + if (['Host'].includes(k)) { + v = `"${v}"`; + } + return `${k}:${v}`; + }) + .join('|'); + if (isNotBlank(value)) { + result.append(`,ws-headers=${value}`); + } + } + } + } else { + throw new Error(`network ${proxy.network} is unsupported`); + } + } +} diff --git a/backend/src/core/proxy-utils/producers/surge.js b/backend/src/core/proxy-utils/producers/surge.js new file mode 100644 index 0000000000..f24b832fa0 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/surge.js @@ -0,0 +1,1134 @@ +import { Result, isPresent } from './utils'; +import { isNotBlank, getIfNotBlank } from '@/utils'; +import $ from '@/core/app'; + +const targetPlatform = 'Surge'; + +const ipVersions = { + dual: 'dual', + ipv4: 'v4-only', + ipv6: 'v6-only', + 'ipv4-prefer': 'prefer-v4', + 'ipv6-prefer': 'prefer-v6', +}; + +export default function Surge_Producer() { + const produce = (proxy, type, opts = {}) => { + proxy.name = proxy.name.replace(/=|,/g, ''); + if (proxy.ports) { + proxy.ports = String(proxy.ports); + } + switch (proxy.type) { + case 'ss': + return shadowsocks(proxy, opts['include-unsupported-proxy']); + case 'trojan': + return trojan(proxy); + case 'vmess': + return vmess(proxy, opts['include-unsupported-proxy']); + case 'http': + return http(proxy); + case 'direct': + return direct(proxy); + case 'socks5': + return socks5(proxy); + case 'snell': + return snell(proxy); + case 'tuic': + return tuic(proxy); + case 'wireguard-surge': + return wireguard_surge(proxy); + case 'hysteria2': + return hysteria2(proxy); + case 'ssh': + return ssh(proxy); + } + + if (opts['include-unsupported-proxy'] && proxy.type === 'wireguard') { + return wireguard(proxy); + } + throw new Error( + `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`, + ); + }; + return { produce }; +} + +function shadowsocks(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`); + if (!proxy.cipher) { + proxy.cipher = 'none'; + } + if ( + ![ + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305', + 'rc4', + 'rc4-md5', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'bf-cfb', + 'camellia-128-cfb', + 'camellia-192-cfb', + 'camellia-256-cfb', + 'cast5-cfb', + 'des-cfb', + 'idea-cfb', + 'rc2-cfb', + 'seed-cfb', + 'salsa20', + 'chacha20', + 'chacha20-ietf', + 'none', + '2022-blake3-aes-128-gcm', + '2022-blake3-aes-256-gcm', + ].includes(proxy.cipher) + ) { + throw new Error(`cipher ${proxy.cipher} is not supported`); + } + result.append(`,encrypt-method=${proxy.cipher}`); + result.appendIfPresent(`,password="${proxy.password}"`, 'password'); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // obfs + if (isPresent(proxy, 'plugin')) { + if (proxy.plugin === 'obfs') { + result.append(`,obfs=${proxy['plugin-opts'].mode}`); + result.appendIfPresent( + `,obfs-host=${proxy['plugin-opts'].host}`, + 'plugin-opts.host', + ); + result.appendIfPresent( + `,obfs-uri=${proxy['plugin-opts'].path}`, + 'plugin-opts.path', + ); + } else if (!['shadow-tls'].includes(proxy.plugin)) { + throw new Error(`plugin ${proxy.plugin} is not supported`); + } + } + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + // udp-port + result.appendIfPresent(`,udp-port=${proxy['udp-port']}`, 'udp-port'); + } else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) { + const password = proxy['plugin-opts'].password; + const host = proxy['plugin-opts'].host; + const version = proxy['plugin-opts'].version; + if (password) { + result.append(`,shadow-tls-password=${password}`); + if (host) { + result.append(`,shadow-tls-sni=${host}`); + } + if (version) { + if (version < 2) { + throw new Error( + `shadow-tls version ${version} is not supported`, + ); + } + result.append(`,shadow-tls-version=${version}`); + } + // udp-port + result.appendIfPresent( + `,udp-port=${proxy['udp-port']}`, + 'udp-port', + ); + } + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} + +function trojan(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,password="${proxy.password}"`, 'password'); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // transport + handleTransport(result, proxy); + + // tls + result.appendIfPresent(`,tls=${proxy.tls}`, 'tls'); + + // tls fingerprint + result.appendIfPresent( + `,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} + +function vmess(proxy, includeUnsupportedProxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,username=${proxy.uuid}`, 'uuid'); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // transport + handleTransport(result, proxy, includeUnsupportedProxy); + + // AEAD + if (isPresent(proxy, 'aead')) { + result.append(`,vmess-aead=${proxy.aead}`); + } else { + result.append(`,vmess-aead=${proxy.alterId === 0}`); + } + + // tls fingerprint + result.appendIfPresent( + `,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls + result.appendIfPresent(`,tls=${proxy.tls}`, 'tls'); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} + +function ssh(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=ssh,${proxy.server},${proxy.port}`); + result.appendIfPresent(`,${proxy.username}`, 'username'); + // 所有的类似的字段都有双引号的问题 暂不处理 + result.appendIfPresent(`,"${proxy.password}"`, 'password'); + + // https://manual.nssurge.com/policy/ssh.html + // 需配合 Keystore + result.appendIfPresent( + `,private-key=${proxy['keystore-private-key']}`, + 'keystore-private-key', + ); + result.appendIfPresent( + `,idle-timeout=${proxy['idle-timeout']}`, + 'idle-timeout', + ); + result.appendIfPresent( + `,server-fingerprint="${proxy['server-fingerprint']}"`, + 'server-fingerprint', + ); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} +function http(proxy) { + if (proxy.headers && Object.keys(proxy.headers).length > 0) { + throw new Error(`headers is unsupported`); + } + const result = new Result(proxy); + const type = proxy.tls ? 'https' : 'http'; + result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,${proxy.username}`, 'username'); + result.appendIfPresent(`,"${proxy.password}"`, 'password'); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // tls fingerprint + result.appendIfPresent( + `,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} +function direct(proxy) { + const result = new Result(proxy); + const type = 'direct'; + result.append(`${proxy.name}=${type}`); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} + +function socks5(proxy) { + const result = new Result(proxy); + const type = proxy.tls ? 'socks5-tls' : 'socks5'; + result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,${proxy.username}`, 'username'); + result.appendIfPresent(`,"${proxy.password}"`, 'password'); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // tls fingerprint + result.appendIfPresent( + `,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tfo + if (proxy.tfo) { + $.info(`Option tfo is not supported by Surge, thus omitted`); + } + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} + +function snell(proxy) { + const result = new Result(proxy); + result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`); + result.appendIfPresent(`,version=${proxy.version}`, 'version'); + result.appendIfPresent(`,psk=${proxy.psk}`, 'psk'); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // obfs + result.appendIfPresent( + `,obfs=${proxy['obfs-opts']?.mode}`, + 'obfs-opts.mode', + ); + result.appendIfPresent( + `,obfs-host=${proxy['obfs-opts']?.host}`, + 'obfs-opts.host', + ); + result.appendIfPresent( + `,obfs-uri=${proxy['obfs-opts']?.path}`, + 'obfs-opts.path', + ); + + // tfo + result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo'); + + // udp + result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + // reuse + result.appendIfPresent(`,reuse=${proxy['reuse']}`, 'reuse'); + + return result.toString(); +} + +function tuic(proxy) { + const result = new Result(proxy); + // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197 + let type = proxy.type; + if (!proxy.token || proxy.token.length === 0) { + type = 'tuic-v5'; + } + result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`); + + result.appendIfPresent(`,uuid=${proxy.uuid}`, 'uuid'); + result.appendIfPresent(`,password="${proxy.password}"`, 'password'); + result.appendIfPresent(`,token=${proxy.token}`, 'token'); + + result.appendIfPresent( + `,alpn=${Array.isArray(proxy.alpn) ? proxy.alpn[0] : proxy.alpn}`, + 'alpn', + ); + + if (isPresent(proxy, 'ports')) { + result.append(`,port-hopping="${proxy.ports.replace(/,/g, ';')}"`); + } + + result.appendIfPresent( + `,port-hopping-interval=${proxy['hop-interval']}`, + 'hop-interval', + ); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + + // tls fingerprint + result.appendIfPresent( + `,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tfo + if (isPresent(proxy, 'tfo')) { + result.append(`,tfo=${proxy['tfo']}`); + } else if (isPresent(proxy, 'fast-open')) { + result.append(`,tfo=${proxy['fast-open']}`); + } + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + result.appendIfPresent(`,ecn=${proxy.ecn}`, 'ecn'); + + return result.toString(); +} + +function wireguard(proxy) { + if (Array.isArray(proxy.peers) && proxy.peers.length > 0) { + proxy.server = proxy.peers[0].server; + proxy.port = proxy.peers[0].port; + proxy.ip = proxy.peers[0].ip; + proxy.ipv6 = proxy.peers[0].ipv6; + proxy['public-key'] = proxy.peers[0]['public-key']; + proxy['preshared-key'] = proxy.peers[0]['pre-shared-key']; + // https://github.com/MetaCubeX/mihomo/blob/0404e35be8736b695eae018a08debb175c1f96e6/docs/config.yaml#L717 + proxy['allowed-ips'] = proxy.peers[0]['allowed-ips']; + proxy.reserved = proxy.peers[0].reserved; + } + const result = new Result(proxy); + + result.append(`# > WireGuard Proxy ${proxy.name} +# ${proxy.name}=wireguard`); + + proxy['section-name'] = getIfNotBlank(proxy['section-name'], proxy.name); + + result.appendIfPresent( + `,section-name=${proxy['section-name']}`, + 'section-name', + ); + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + result.append(` +# > WireGuard Section ${proxy.name} +[WireGuard ${proxy['section-name']}] +private-key = ${proxy['private-key']}`); + + result.appendIfPresent(`\nself-ip = ${proxy.ip}`, 'ip'); + result.appendIfPresent(`\nself-ip-v6 = ${proxy.ipv6}`, 'ipv6'); + if (proxy.dns) { + if (Array.isArray(proxy.dns)) { + proxy.dns = proxy.dns.join(', '); + } + result.append(`\ndns-server = ${proxy.dns}`); + } + result.appendIfPresent(`\nmtu = ${proxy.mtu}`, 'mtu'); + + if (ip_version === 'prefer-v6') { + result.append(`\nprefer-ipv6 = true`); + } + const allowedIps = Array.isArray(proxy['allowed-ips']) + ? proxy['allowed-ips'].join(',') + : proxy['allowed-ips']; + let reserved = Array.isArray(proxy.reserved) + ? proxy.reserved.join('/') + : proxy.reserved; + let presharedKey = proxy['preshared-key'] ?? proxy['pre-shared-key']; + if (presharedKey) { + presharedKey = `,preshared-key="${presharedKey}"`; + } + const peer = { + 'public-key': proxy['public-key'], + 'allowed-ips': allowedIps ? `"${allowedIps}"` : undefined, + endpoint: `${proxy.server}:${proxy.port}`, + keepalive: proxy['persistent-keepalive'] || proxy.keepalive, + 'client-id': reserved, + 'preshared-key': presharedKey, + }; + result.append( + `\npeer = (${Object.keys(peer) + .filter((k) => peer[k] != null) + .map((k) => `${k} = ${peer[k]}`) + .join(', ')})`, + ); + return result.toString(); +} +function wireguard_surge(proxy) { + const result = new Result(proxy); + + result.append(`${proxy.name}=wireguard`); + + result.appendIfPresent( + `,section-name=${proxy['section-name']}`, + 'section-name', + ); + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + return result.toString(); +} + +function hysteria2(proxy) { + if (proxy.obfs || proxy['obfs-password']) { + throw new Error(`obfs is unsupported`); + } + const result = new Result(proxy); + result.append(`${proxy.name}=hysteria2,${proxy.server},${proxy.port}`); + + result.appendIfPresent(`,password="${proxy.password}"`, 'password'); + + if (isPresent(proxy, 'ports')) { + result.append(`,port-hopping="${proxy.ports.replace(/,/g, ';')}"`); + } + + result.appendIfPresent( + `,port-hopping-interval=${proxy['hop-interval']}`, + 'hop-interval', + ); + + const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version']; + result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version'); + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // tls verification + result.appendIfPresent(`,sni=${proxy.sni}`, 'sni'); + result.appendIfPresent( + `,skip-cert-verify=${proxy['skip-cert-verify']}`, + 'skip-cert-verify', + ); + result.appendIfPresent( + `,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`, + 'tls-fingerprint', + ); + + // tfo + if (isPresent(proxy, 'tfo')) { + result.append(`,tfo=${proxy['tfo']}`); + } else if (isPresent(proxy, 'fast-open')) { + result.append(`,tfo=${proxy['fast-open']}`); + } + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + result.appendIfPresent( + `,test-timeout=${proxy['test-timeout']}`, + 'test-timeout', + ); + result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp'); + result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid'); + result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos'); + result.appendIfPresent( + `,allow-other-interface=${proxy['allow-other-interface']}`, + 'allow-other-interface', + ); + result.appendIfPresent( + `,interface=${proxy['interface-name']}`, + 'interface-name', + ); + + // shadow-tls + if (isPresent(proxy, 'shadow-tls-password')) { + result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`); + + result.appendIfPresent( + `,shadow-tls-version=${proxy['shadow-tls-version']}`, + 'shadow-tls-version', + ); + result.appendIfPresent( + `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, + 'shadow-tls-sni', + ); + } + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + // underlying-proxy + result.appendIfPresent( + `,underlying-proxy=${proxy['underlying-proxy']}`, + 'underlying-proxy', + ); + + // download-bandwidth + result.appendIfPresent( + `,download-bandwidth=${`${proxy['down']}`.match(/\d+/)?.[0] || 0}`, + 'down', + ); + + result.appendIfPresent(`,ecn=${proxy.ecn}`, 'ecn'); + + return result.toString(); +} + +function handleTransport(result, proxy, includeUnsupportedProxy) { + if (isPresent(proxy, 'network')) { + if (proxy.network === 'ws') { + result.append(`,ws=true`); + if (isPresent(proxy, 'ws-opts')) { + result.appendIfPresent( + `,ws-path=${proxy['ws-opts'].path}`, + 'ws-opts.path', + ); + if (isPresent(proxy, 'ws-opts.headers')) { + const headers = proxy['ws-opts'].headers; + const value = Object.keys(headers) + .map((k) => { + let v = headers[k]; + if (['Host'].includes(k)) { + v = `"${v}"`; + } + return `${k}:${v}`; + }) + .join('|'); + if (isNotBlank(value)) { + result.append(`,ws-headers=${value}`); + } + } + } + } else { + if (includeUnsupportedProxy && ['http'].includes(proxy.network)) { + $.info( + `Include Unsupported Proxy: nework ${proxy.network} -> tcp`, + ); + } else { + throw new Error(`network ${proxy.network} is unsupported`); + } + } + } +} diff --git a/backend/src/core/proxy-utils/producers/surgemac.js b/backend/src/core/proxy-utils/producers/surgemac.js new file mode 100644 index 0000000000..ba3dc20612 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/surgemac.js @@ -0,0 +1,192 @@ +import { Base64 } from 'js-base64'; +import { Result, isPresent } from './utils'; +import Surge_Producer from './surge'; +import ClashMeta_Producer from './clashmeta'; +import { isIPv4, isIPv6 } from '@/utils'; +import $ from '@/core/app'; + +const targetPlatform = 'SurgeMac'; + +const surge_Producer = Surge_Producer(); + +export default function SurgeMac_Producer() { + const produce = (proxy, type, opts = {}) => { + switch (proxy.type) { + case 'external': + return external(proxy); + // case 'ssr': + // return shadowsocksr(proxy); + default: { + try { + return surge_Producer.produce(proxy, type, opts); + } catch (e) { + if (opts.useMihomoExternal) { + $.log( + `${proxy.name} is not supported on ${targetPlatform}, try to use Mihomo(SurgeMac - External Proxy Program) instead`, + ); + return mihomo(proxy, type, opts); + } else { + throw new Error( + `Surge for macOS 可手动指定链接参数 target=SurgeMac 或在 同步配置 中指定 SurgeMac 来启用 mihomo 支援 Surge 本身不支持的协议`, + ); + } + } + } + } + }; + return { produce }; +} +function external(proxy) { + const result = new Result(proxy); + if (!proxy.exec || !proxy['local-port']) { + throw new Error(`${proxy.type}: exec and local-port are required`); + } + result.append( + `${proxy.name}=external,exec="${proxy.exec}",local-port=${proxy['local-port']}`, + ); + + if (Array.isArray(proxy.args)) { + proxy.args.map((args) => { + result.append(`,args="${args}"`); + }); + } + if (Array.isArray(proxy.addresses)) { + proxy.addresses.map((addresses) => { + result.append(`,addresses=${addresses}`); + }); + } + + result.appendIfPresent( + `,no-error-alert=${proxy['no-error-alert']}`, + 'no-error-alert', + ); + + // tfo + if (isPresent(proxy, 'tfo')) { + result.append(`,tfo=${proxy['tfo']}`); + } else if (isPresent(proxy, 'fast-open')) { + result.append(`,tfo=${proxy['fast-open']}`); + } + + // test-url + result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url'); + + // block-quic + result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic'); + + return result.toString(); +} +// eslint-disable-next-line no-unused-vars +function shadowsocksr(proxy) { + const external_proxy = { + ...proxy, + type: 'external', + exec: proxy.exec || '/usr/local/bin/ssr-local', + 'local-port': '__SubStoreLocalPort__', + args: [], + addresses: [], + 'local-address': + proxy.local_address ?? proxy['local-address'] ?? '127.0.0.1', + }; + + // https://manual.nssurge.com/policy/external-proxy.html + if (isIP(proxy.server)) { + external_proxy.addresses.push(proxy.server); + } else { + $.log( + `Platform ${targetPlatform}, proxy type ${proxy.type}: addresses should be an IP address, but got ${proxy.server}`, + ); + } + + for (const [key, value] of Object.entries({ + cipher: '-m', + obfs: '-o', + 'obfs-param': '-g', + password: '-k', + port: '-p', + protocol: '-O', + 'protocol-param': '-G', + server: '-s', + 'local-port': '-l', + 'local-address': '-b', + })) { + if (external_proxy[key] != null) { + external_proxy.args.push(value); + external_proxy.args.push(external_proxy[key]); + } + } + + return external(external_proxy); +} +// eslint-disable-next-line no-unused-vars +function mihomo(proxy, type, opts) { + const clashProxy = ClashMeta_Producer().produce([proxy], 'internal')?.[0]; + if (clashProxy) { + const localPort = opts?.localPort || proxy._localPort || 65535; + const ipv6 = ['ipv4', 'v4-only'].includes(proxy['ip-version']) + ? false + : true; + const external_proxy = { + name: proxy.name, + type: 'external', + exec: proxy._exec || '/usr/local/bin/mihomo', + 'local-port': localPort, + args: [ + '-config', + Base64.encode( + JSON.stringify({ + 'mixed-port': localPort, + ipv6, + mode: 'global', + dns: { + enable: true, + ipv6, + 'default-nameserver': opts?.defaultNameserver || + proxy._defaultNameserver || [ + '180.76.76.76', + '52.80.52.52', + '119.28.28.28', + '223.6.6.6', + ], + nameserver: opts?.nameserver || + proxy._nameserver || [ + 'https://doh.pub/dns-query', + 'https://dns.alidns.com/dns-query', + 'https://doh-pure.onedns.net/dns-query', + ], + }, + proxies: [ + { + ...clashProxy, + name: 'proxy', + }, + ], + 'proxy-groups': [ + { + name: 'GLOBAL', + type: 'select', + proxies: ['proxy'], + }, + ], + }), + ), + ], + addresses: [], + }; + + // https://manual.nssurge.com/policy/external-proxy.html + if (isIP(proxy.server)) { + external_proxy.addresses.push(proxy.server); + } else { + $.log( + `Platform ${targetPlatform}, proxy type ${proxy.type}: addresses should be an IP address, but got ${proxy.server}`, + ); + } + opts.localPort = localPort - 1; + return external(external_proxy); + } +} + +function isIP(ip) { + return isIPv4(ip) || isIPv6(ip); +} diff --git a/backend/src/core/proxy-utils/producers/uri.js b/backend/src/core/proxy-utils/producers/uri.js new file mode 100644 index 0000000000..a93cfd34ff --- /dev/null +++ b/backend/src/core/proxy-utils/producers/uri.js @@ -0,0 +1,659 @@ +/* eslint-disable no-case-declarations */ +import { Base64 } from 'js-base64'; +import { isIPv6 } from '@/utils'; + +export default function URI_Producer() { + const type = 'SINGLE'; + const produce = (proxy) => { + let result = ''; + delete proxy.subName; + delete proxy.collectionName; + delete proxy.id; + delete proxy.resolved; + delete proxy['no-resolve']; + for (const key in proxy) { + if (proxy[key] == null) { + delete proxy[key]; + } + } + if ( + ['trojan', 'tuic', 'hysteria', 'hysteria2', 'juicity'].includes( + proxy.type, + ) + ) { + delete proxy.tls; + } + if ( + !['vmess'].includes(proxy.type) && + proxy.server && + isIPv6(proxy.server) + ) { + proxy.server = `[${proxy.server}]`; + } + switch (proxy.type) { + case 'socks5': + result = `socks://${encodeURIComponent( + Base64.encode(`${proxy.username}:${proxy.password}`), + )}@${proxy.server}:${proxy.port}#${proxy.name}`; + break; + case 'ss': + const userinfo = `${proxy.cipher}:${proxy.password}`; + result = `ss://${ + proxy.cipher?.startsWith('2022-blake3-') + ? `${encodeURIComponent( + proxy.cipher, + )}:${encodeURIComponent(proxy.password)}` + : Base64.encode(userinfo) + }@${proxy.server}:${proxy.port}${proxy.plugin ? '/' : ''}`; + if (proxy.plugin) { + result += '?plugin='; + const opts = proxy['plugin-opts']; + switch (proxy.plugin) { + case 'obfs': + result += encodeURIComponent( + `simple-obfs;obfs=${opts.mode}${ + opts.host ? ';obfs-host=' + opts.host : '' + }`, + ); + break; + case 'v2ray-plugin': + result += encodeURIComponent( + `v2ray-plugin;obfs=${opts.mode}${ + opts.host ? ';obfs-host' + opts.host : '' + }${opts.tls ? ';tls' : ''}`, + ); + break; + case 'shadow-tls': + result += encodeURIComponent( + `shadow-tls;host=${opts.host};password=${opts.password};version=${opts.version}`, + ); + break; + default: + throw new Error( + `Unsupported plugin option: ${proxy.plugin}`, + ); + } + } + if (proxy['udp-over-tcp']) { + result = `${result}${proxy.plugin ? '&' : '?'}uot=1`; + } + if (proxy.tfo) { + result = `${result}${ + proxy.plugin || proxy['udp-over-tcp'] ? '&' : '?' + }tfo=1`; + } + result += `#${encodeURIComponent(proxy.name)}`; + break; + case 'ssr': + result = `${proxy.server}:${proxy.port}:${proxy.protocol}:${ + proxy.cipher + }:${proxy.obfs}:${Base64.encode(proxy.password)}/`; + result += `?remarks=${Base64.encode(proxy.name)}${ + proxy['obfs-param'] + ? '&obfsparam=' + Base64.encode(proxy['obfs-param']) + : '' + }${ + proxy['protocol-param'] + ? '&protocolparam=' + + Base64.encode(proxy['protocol-param']) + : '' + }`; + result = 'ssr://' + Base64.encode(result); + break; + case 'vmess': + // V2RayN URI format + let type = ''; + let net = proxy.network || 'tcp'; + if (proxy.network === 'http') { + net = 'tcp'; + type = 'http'; + } else if ( + proxy.network === 'ws' && + proxy['ws-opts']?.['v2ray-http-upgrade'] + ) { + net = 'httpupgrade'; + } + result = { + v: '2', + ps: proxy.name, + add: proxy.server, + port: proxy.port, + id: proxy.uuid, + type, + aid: proxy.alterId || 0, + net, + tls: proxy.tls ? 'tls' : '', + }; + if (proxy.tls && proxy.sni) { + result.sni = proxy.sni; + } + // obfs + if (proxy.network) { + let vmessTransportPath = + proxy[`${proxy.network}-opts`]?.path; + let vmessTransportHost = + proxy[`${proxy.network}-opts`]?.headers?.Host; + if (vmessTransportPath) { + result.path = Array.isArray(vmessTransportPath) + ? vmessTransportPath[0] + : vmessTransportPath; + } + if (vmessTransportHost) { + result.host = Array.isArray(vmessTransportHost) + ? vmessTransportHost[0] + : vmessTransportHost; + } + if (['grpc'].includes(proxy.network)) { + result.path = + proxy[`${proxy.network}-opts`]?.[ + 'grpc-service-name' + ]; + // https://github.com/XTLS/Xray-core/issues/91 + result.type = + proxy[`${proxy.network}-opts`]?.['_grpc-type'] || + 'gun'; + result.host = + proxy[`${proxy.network}-opts`]?.['_grpc-authority']; + } + } + result = 'vmess://' + Base64.encode(JSON.stringify(result)); + break; + case 'vless': + let security = 'none'; + const isReality = proxy['reality-opts']; + let sid = ''; + let pbk = ''; + let spx = ''; + if (isReality) { + security = 'reality'; + const publicKey = proxy['reality-opts']?.['public-key']; + if (publicKey) { + pbk = `&pbk=${encodeURIComponent(publicKey)}`; + } + const shortId = proxy['reality-opts']?.['short-id']; + if (shortId) { + sid = `&sid=${encodeURIComponent(shortId)}`; + } + const spiderX = proxy['reality-opts']?.['_spider-x']; + if (spiderX) { + spx = `&spx=${encodeURIComponent(spiderX)}`; + } + } else if (proxy.tls) { + security = 'tls'; + } + let alpn = ''; + if (proxy.alpn) { + alpn = `&alpn=${encodeURIComponent( + Array.isArray(proxy.alpn) + ? proxy.alpn + : proxy.alpn.join(','), + )}`; + } + let allowInsecure = ''; + if (proxy['skip-cert-verify']) { + allowInsecure = `&allowInsecure=1`; + } + let sni = ''; + if (proxy.sni) { + sni = `&sni=${encodeURIComponent(proxy.sni)}`; + } + let fp = ''; + if (proxy['client-fingerprint']) { + fp = `&fp=${encodeURIComponent( + proxy['client-fingerprint'], + )}`; + } + let flow = ''; + if (proxy.flow) { + flow = `&flow=${encodeURIComponent(proxy.flow)}`; + } + let extra = ''; + if (proxy._extra) { + extra = `&extra=${encodeURIComponent(proxy._extra)}`; + } + let mode = ''; + if (proxy._mode) { + mode = `&mode=${encodeURIComponent(proxy._mode)}`; + } + let vlessType = proxy.network; + if ( + proxy.network === 'ws' && + proxy['ws-opts']?.['v2ray-http-upgrade'] + ) { + vlessType = 'httpupgrade'; + } + + let vlessTransport = `&type=${encodeURIComponent(vlessType)}`; + if (['grpc'].includes(proxy.network)) { + // https://github.com/XTLS/Xray-core/issues/91 + vlessTransport += `&mode=${encodeURIComponent( + proxy[`${proxy.network}-opts`]?.['_grpc-type'] || 'gun', + )}`; + const authority = + proxy[`${proxy.network}-opts`]?.['_grpc-authority']; + if (authority) { + vlessTransport += `&authority=${encodeURIComponent( + authority, + )}`; + } + } + + let vlessTransportServiceName = + proxy[`${proxy.network}-opts`]?.[ + `${proxy.network}-service-name` + ]; + let vlessTransportPath = proxy[`${proxy.network}-opts`]?.path; + let vlessTransportHost = + proxy[`${proxy.network}-opts`]?.headers?.Host; + if (vlessTransportPath) { + vlessTransport += `&path=${encodeURIComponent( + Array.isArray(vlessTransportPath) + ? vlessTransportPath[0] + : vlessTransportPath, + )}`; + } + if (vlessTransportHost) { + vlessTransport += `&host=${encodeURIComponent( + Array.isArray(vlessTransportHost) + ? vlessTransportHost[0] + : vlessTransportHost, + )}`; + } + if (vlessTransportServiceName) { + vlessTransport += `&serviceName=${encodeURIComponent( + vlessTransportServiceName, + )}`; + } + if (proxy.network === 'kcp') { + if (proxy.seed) { + vlessTransport += `&seed=${encodeURIComponent( + proxy.seed, + )}`; + } + if (proxy.headerType) { + vlessTransport += `&headerType=${encodeURIComponent( + proxy.headerType, + )}`; + } + } + + result = `vless://${proxy.uuid}@${proxy.server}:${ + proxy.port + }?security=${encodeURIComponent( + security, + )}${vlessTransport}${alpn}${allowInsecure}${sni}${fp}${flow}${sid}${spx}${pbk}${mode}${extra}#${encodeURIComponent( + proxy.name, + )}`; + break; + case 'trojan': + let trojanTransport = ''; + if (proxy.network) { + let trojanType = proxy.network; + if ( + proxy.network === 'ws' && + proxy['ws-opts']?.['v2ray-http-upgrade'] + ) { + trojanType = 'httpupgrade'; + } + trojanTransport = `&type=${encodeURIComponent(trojanType)}`; + if (['grpc'].includes(proxy.network)) { + let trojanTransportServiceName = + proxy[`${proxy.network}-opts`]?.[ + `${proxy.network}-service-name` + ]; + let trojanTransportAuthority = + proxy[`${proxy.network}-opts`]?.['_grpc-authority']; + if (trojanTransportServiceName) { + trojanTransport += `&serviceName=${encodeURIComponent( + trojanTransportServiceName, + )}`; + } + if (trojanTransportAuthority) { + trojanTransport += `&authority=${encodeURIComponent( + trojanTransportAuthority, + )}`; + } + trojanTransport += `&mode=${encodeURIComponent( + proxy[`${proxy.network}-opts`]?.['_grpc-type'] || + 'gun', + )}`; + } + let trojanTransportPath = + proxy[`${proxy.network}-opts`]?.path; + let trojanTransportHost = + proxy[`${proxy.network}-opts`]?.headers?.Host; + if (trojanTransportPath) { + trojanTransport += `&path=${encodeURIComponent( + Array.isArray(trojanTransportPath) + ? trojanTransportPath[0] + : trojanTransportPath, + )}`; + } + if (trojanTransportHost) { + trojanTransport += `&host=${encodeURIComponent( + Array.isArray(trojanTransportHost) + ? trojanTransportHost[0] + : trojanTransportHost, + )}`; + } + } + let trojanFp = ''; + if (proxy['client-fingerprint']) { + trojanFp = `&fp=${encodeURIComponent( + proxy['client-fingerprint'], + )}`; + } + let trojanAlpn = ''; + if (proxy.alpn) { + trojanAlpn = `&alpn=${encodeURIComponent( + Array.isArray(proxy.alpn) + ? proxy.alpn + : proxy.alpn.join(','), + )}`; + } + const trojanIsReality = proxy['reality-opts']; + let trojanSid = ''; + let trojanPbk = ''; + let trojanSpx = ''; + let trojanSecurity = ''; + let trojanMode = ''; + let trojanExtra = ''; + if (trojanIsReality) { + trojanSecurity = `&security=reality`; + const publicKey = proxy['reality-opts']?.['public-key']; + if (publicKey) { + trojanPbk = `&pbk=${encodeURIComponent(publicKey)}`; + } + const shortId = proxy['reality-opts']?.['short-id']; + if (shortId) { + trojanSid = `&sid=${encodeURIComponent(shortId)}`; + } + const spiderX = proxy['reality-opts']?.['_spider-x']; + if (spiderX) { + trojanSpx = `&spx=${encodeURIComponent(spiderX)}`; + } + if (proxy._extra) { + trojanExtra = `&extra=${encodeURIComponent( + proxy._extra, + )}`; + } + if (proxy._mode) { + trojanMode = `&mode=${encodeURIComponent(proxy._mode)}`; + } + } + result = `trojan://${proxy.password}@${proxy.server}:${ + proxy.port + }?sni=${encodeURIComponent(proxy.sni || proxy.server)}${ + proxy['skip-cert-verify'] ? '&allowInsecure=1' : '' + }${trojanTransport}${trojanAlpn}${trojanFp}${trojanSecurity}${trojanSid}${trojanPbk}${trojanSpx}${trojanMode}${trojanExtra}#${encodeURIComponent( + proxy.name, + )}`; + break; + case 'hysteria2': + let hysteria2params = []; + if (proxy['hop-interval']) { + hysteria2params.push( + `hop-interval=${proxy['hop-interval']}`, + ); + } + if (proxy['keepalive']) { + hysteria2params.push(`keepalive=${proxy['keepalive']}`); + } + if (proxy['skip-cert-verify']) { + hysteria2params.push(`insecure=1`); + } + if (proxy.obfs) { + hysteria2params.push( + `obfs=${encodeURIComponent(proxy.obfs)}`, + ); + if (proxy['obfs-password']) { + hysteria2params.push( + `obfs-password=${encodeURIComponent( + proxy['obfs-password'], + )}`, + ); + } + } + if (proxy.sni) { + hysteria2params.push( + `sni=${encodeURIComponent(proxy.sni)}`, + ); + } + if (proxy.ports) { + hysteria2params.push(`mport=${proxy.ports}`); + } + if (proxy['tls-fingerprint']) { + hysteria2params.push( + `pinSHA256=${encodeURIComponent( + proxy['tls-fingerprint'], + )}`, + ); + } + if (proxy.tfo) { + hysteria2params.push(`fastopen=1`); + } + result = `hysteria2://${encodeURIComponent(proxy.password)}@${ + proxy.server + }:${proxy.port}?${hysteria2params.join( + '&', + )}#${encodeURIComponent(proxy.name)}`; + break; + case 'hysteria': + let hysteriaParams = []; + Object.keys(proxy).forEach((key) => { + if (!['name', 'type', 'server', 'port'].includes(key)) { + const i = key.replace(/-/, '_'); + if (['alpn'].includes(key)) { + if (proxy[key]) { + hysteriaParams.push( + `${i}=${encodeURIComponent( + Array.isArray(proxy[key]) + ? proxy[key][0] + : proxy[key], + )}`, + ); + } + } else if (['skip-cert-verify'].includes(key)) { + if (proxy[key]) { + hysteriaParams.push(`insecure=1`); + } + } else if (['tfo', 'fast-open'].includes(key)) { + if ( + proxy[key] && + !hysteriaParams.includes('fastopen=1') + ) { + hysteriaParams.push(`fastopen=1`); + } + } else if (['ports'].includes(key)) { + hysteriaParams.push(`mport=${proxy[key]}`); + } else if (['auth-str'].includes(key)) { + hysteriaParams.push(`auth=${proxy[key]}`); + } else if (['up'].includes(key)) { + hysteriaParams.push(`upmbps=${proxy[key]}`); + } else if (['down'].includes(key)) { + hysteriaParams.push(`downmbps=${proxy[key]}`); + } else if (['_obfs'].includes(key)) { + hysteriaParams.push(`obfs=${proxy[key]}`); + } else if (['obfs'].includes(key)) { + hysteriaParams.push(`obfsParam=${proxy[key]}`); + } else if (['sni'].includes(key)) { + hysteriaParams.push(`peer=${proxy[key]}`); + } else if (proxy[key] && !/^_/i.test(key)) { + hysteriaParams.push( + `${i}=${encodeURIComponent(proxy[key])}`, + ); + } + } + }); + + result = `hysteria://${proxy.server}:${ + proxy.port + }?${hysteriaParams.join('&')}#${encodeURIComponent( + proxy.name, + )}`; + break; + + case 'tuic': + if (!proxy.token || proxy.token.length === 0) { + let tuicParams = []; + Object.keys(proxy).forEach((key) => { + if ( + ![ + 'name', + 'type', + 'uuid', + 'password', + 'server', + 'port', + 'tls', + ].includes(key) + ) { + const i = key.replace(/-/, '_'); + if (['alpn'].includes(key)) { + if (proxy[key]) { + tuicParams.push( + `${i}=${encodeURIComponent( + Array.isArray(proxy[key]) + ? proxy[key][0] + : proxy[key], + )}`, + ); + } + } else if (['skip-cert-verify'].includes(key)) { + if (proxy[key]) { + tuicParams.push(`allow_insecure=1`); + } + } else if (['tfo', 'fast-open'].includes(key)) { + if ( + proxy[key] && + !tuicParams.includes('fast_open=1') + ) { + tuicParams.push(`fast_open=1`); + } + } else if ( + ['disable-sni', 'reduce-rtt'].includes(key) && + proxy[key] + ) { + tuicParams.push(`${i.replace(/-/g, '_')}=1`); + } else if ( + ['congestion-controller'].includes(key) + ) { + tuicParams.push( + `congestion_control=${proxy[key]}`, + ); + } else if (proxy[key] && !/^_/i.test(key)) { + tuicParams.push( + `${i.replace( + /-/g, + '_', + )}=${encodeURIComponent(proxy[key])}`, + ); + } + } + }); + + result = `tuic://${encodeURIComponent( + proxy.uuid, + )}:${encodeURIComponent(proxy.password)}@${proxy.server}:${ + proxy.port + }?${tuicParams.join('&')}#${encodeURIComponent( + proxy.name, + )}`; + } + break; + case 'anytls': + let anytlsParams = []; + Object.keys(proxy).forEach((key) => { + if ( + ![ + 'name', + 'type', + 'password', + 'server', + 'port', + 'tls', + ].includes(key) + ) { + const i = key.replace(/-/, '_'); + if (['alpn'].includes(key)) { + if (proxy[key]) { + anytlsParams.push( + `${i}=${encodeURIComponent( + Array.isArray(proxy[key]) + ? proxy[key][0] + : proxy[key], + )}`, + ); + } + } else if (['skip-cert-verify'].includes(key)) { + if (proxy[key]) { + anytlsParams.push(`insecure=1`); + } + } else if (['udp'].includes(key)) { + if (proxy[key]) { + anytlsParams.push(`udp=1`); + } + } else if (proxy[key] && !/^_/i.test(key)) { + anytlsParams.push( + `${i.replace(/-/g, '_')}=${encodeURIComponent( + proxy[key], + )}`, + ); + } + } + }); + + result = `anytls://${encodeURIComponent(proxy.password)}@${ + proxy.server + }:${proxy.port}/?${anytlsParams.join('&')}#${encodeURIComponent( + proxy.name, + )}`; + break; + case 'wireguard': + let wireguardParams = []; + + Object.keys(proxy).forEach((key) => { + if ( + ![ + 'name', + 'type', + 'server', + 'port', + 'ip', + 'ipv6', + 'private-key', + ].includes(key) + ) { + if (['public-key'].includes(key)) { + wireguardParams.push(`publickey=${proxy[key]}`); + } else if (['udp'].includes(key)) { + if (proxy[key]) { + wireguardParams.push(`${key}=1`); + } + } else if (proxy[key] && !/^_/i.test(key)) { + wireguardParams.push( + `${key}=${encodeURIComponent(proxy[key])}`, + ); + } + } + }); + if (proxy.ip && proxy.ipv6) { + wireguardParams.push( + `address=${proxy.ip}/32,${proxy.ipv6}/128`, + ); + } else if (proxy.ip) { + wireguardParams.push(`address=${proxy.ip}/32`); + } else if (proxy.ipv6) { + wireguardParams.push(`address=${proxy.ipv6}/128`); + } + result = `wireguard://${encodeURIComponent( + proxy['private-key'], + )}@${proxy.server}:${proxy.port}/?${wireguardParams.join( + '&', + )}#${encodeURIComponent(proxy.name)}`; + break; + } + return result; + }; + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/producers/utils.js b/backend/src/core/proxy-utils/producers/utils.js new file mode 100644 index 0000000000..e8dc964d08 --- /dev/null +++ b/backend/src/core/proxy-utils/producers/utils.js @@ -0,0 +1,30 @@ +import _ from 'lodash'; + +export class Result { + constructor(proxy) { + this.proxy = proxy; + this.output = []; + } + + append(data) { + if (typeof data === 'undefined') { + throw new Error('required field is missing'); + } + this.output.push(data); + } + + appendIfPresent(data, attr) { + if (isPresent(this.proxy, attr)) { + this.append(data); + } + } + + toString() { + return this.output.join(''); + } +} + +export function isPresent(obj, attr) { + const data = _.get(obj, attr); + return typeof data !== 'undefined' && data !== null; +} diff --git a/backend/src/core/proxy-utils/producers/v2ray.js b/backend/src/core/proxy-utils/producers/v2ray.js new file mode 100644 index 0000000000..bdb3c68d5d --- /dev/null +++ b/backend/src/core/proxy-utils/producers/v2ray.js @@ -0,0 +1,30 @@ +/* eslint-disable no-case-declarations */ +import { Base64 } from 'js-base64'; +import URI_Producer from './uri'; +import $ from '@/core/app'; + +const URI = URI_Producer(); + +export default function V2Ray_Producer() { + const type = 'ALL'; + const produce = (proxies) => { + let result = []; + proxies.map((proxy) => { + try { + result.push(URI.produce(proxy)); + } catch (err) { + $.error( + `Cannot produce proxy: ${JSON.stringify( + proxy, + null, + 2, + )}\nReason: ${err}`, + ); + } + }); + + return Base64.encode(result.join('\n')); + }; + + return { type, produce }; +} diff --git a/backend/src/core/proxy-utils/validators/index.js b/backend/src/core/proxy-utils/validators/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/src/core/rule-utils/index.js b/backend/src/core/rule-utils/index.js new file mode 100644 index 0000000000..0152d71ede --- /dev/null +++ b/backend/src/core/rule-utils/index.js @@ -0,0 +1,69 @@ +import RULE_PREPROCESSORS from './preprocessors'; +import RULE_PRODUCERS from './producers'; +import RULE_PARSERS from './parsers'; +import $ from '@/core/app'; + +export const RuleUtils = (function () { + function preprocess(raw) { + for (const processor of RULE_PREPROCESSORS) { + try { + if (processor.test(raw)) { + $.info(`Pre-processor [${processor.name}] activated`); + return processor.parse(raw); + } + } catch (e) { + $.error(`Parser [${processor.name}] failed\n Reason: ${e}`); + } + } + return raw; + } + + function parse(raw) { + raw = preprocess(raw); + for (const parser of RULE_PARSERS) { + let matched; + try { + matched = parser.test(raw); + } catch (err) { + matched = false; + } + if (matched) { + $.info(`Rule parser [${parser.name}] is activated!`); + return parser.parse(raw); + } + } + } + + function produce(rules, targetPlatform) { + const producer = RULE_PRODUCERS[targetPlatform]; + if (!producer) { + throw new Error( + `Target platform: ${targetPlatform} is not supported!`, + ); + } + if ( + typeof producer.type === 'undefined' || + producer.type === 'SINGLE' + ) { + return rules + .map((rule) => { + try { + return producer.func(rule); + } catch (err) { + console.log( + `ERROR: cannot produce rule: ${JSON.stringify( + rule, + )}\nReason: ${err}`, + ); + return ''; + } + }) + .filter((line) => line.length > 0) + .join('\n'); + } else if (producer.type === 'ALL') { + return producer.func(rules); + } + } + + return { parse, produce }; +})(); diff --git a/backend/src/core/rule-utils/parsers.js b/backend/src/core/rule-utils/parsers.js new file mode 100644 index 0000000000..755665243c --- /dev/null +++ b/backend/src/core/rule-utils/parsers.js @@ -0,0 +1,59 @@ +const RULE_TYPES_MAPPING = [ + [/^(DOMAIN|host|HOST)$/, 'DOMAIN'], + [/^(DOMAIN-KEYWORD|host-keyword|HOST-KEYWORD)$/, 'DOMAIN-KEYWORD'], + [/^(DOMAIN-SUFFIX|host-suffix|HOST-SUFFIX)$/, 'DOMAIN-SUFFIX'], + [/^USER-AGENT$/i, 'USER-AGENT'], + [/^PROCESS-NAME$/, 'PROCESS-NAME'], + [/^(DEST-PORT|DST-PORT)$/, 'DST-PORT'], + [/^SRC-IP(-CIDR)?$/, 'SRC-IP'], + [/^(IN|SRC)-PORT$/, 'IN-PORT'], + [/^PROTOCOL$/, 'PROTOCOL'], + [/^IP-CIDR$/i, 'IP-CIDR'], + [/^(IP-CIDR6|ip6-cidr|IP6-CIDR)$/, 'IP-CIDR6'], + [/^GEOIP$/i, 'GEOIP'], + [/^GEOSITE$/i, 'GEOSITE'], +]; + +function AllRuleParser() { + const name = 'Universal Rule Parser'; + const test = () => true; + const parse = (raw) => { + const lines = raw.split('\n'); + const result = []; + for (let line of lines) { + line = line.trim(); + // skip empty line + if (line.length === 0) continue; + // skip comments + if (/\s*#/.test(line)) continue; + try { + const params = line.split(',').map((w) => w.trim()); + let rawType = params[0]; + let matched = false; + for (const item of RULE_TYPES_MAPPING) { + const regex = item[0]; + if (regex.test(rawType)) { + matched = true; + const rule = { + type: item[1], + content: params[1], + }; + if ( + ['IP-CIDR', 'IP-CIDR6', 'GEOIP'].includes(rule.type) + ) { + rule.options = params.slice(2); + } + result.push(rule); + } + } + if (!matched) throw new Error('Invalid rule type: ' + rawType); + } catch (e) { + console.log(`Failed to parse line: ${line}\n Reason: ${e}`); + } + } + return result; + }; + return { name, test, parse }; +} + +export default [AllRuleParser()]; diff --git a/backend/src/core/rule-utils/preprocessors.js b/backend/src/core/rule-utils/preprocessors.js new file mode 100644 index 0000000000..8e78d128f8 --- /dev/null +++ b/backend/src/core/rule-utils/preprocessors.js @@ -0,0 +1,18 @@ +function HTML() { + const name = 'HTML'; + const test = (raw) => /^/.test(raw); + // simply discard HTML + const parse = () => ''; + return { name, test, parse }; +} + +function ClashProvider() { + const name = 'Clash Provider'; + const test = (raw) => /^payload:/gm.exec(raw).index >= 0; + const parse = (raw) => { + return raw.replace('payload:', '').replace(/^\s*-\s*/gm, ''); + }; + return { name, test, parse }; +} + +export default [HTML(), ClashProvider()]; diff --git a/backend/src/core/rule-utils/producers.js b/backend/src/core/rule-utils/producers.js new file mode 100644 index 0000000000..d11577ffe1 --- /dev/null +++ b/backend/src/core/rule-utils/producers.js @@ -0,0 +1,101 @@ +import YAML from '@/utils/yaml'; + +function QXFilter() { + const type = 'SINGLE'; + const func = (rule) => { + // skip unsupported rules + const UNSUPPORTED = [ + 'URL-REGEX', + 'DEST-PORT', + 'SRC-IP', + 'IN-PORT', + 'PROTOCOL', + 'GEOSITE', + 'GEOIP', + ]; + if (UNSUPPORTED.indexOf(rule.type) !== -1) return null; + + const TRANSFORM = { + 'DOMAIN-KEYWORD': 'HOST-KEYWORD', + 'DOMAIN-SUFFIX': 'HOST-SUFFIX', + DOMAIN: 'HOST', + 'IP-CIDR6': 'IP6-CIDR', + }; + + // QX does not support the no-resolve option + return `${TRANSFORM[rule.type] || rule.type},${rule.content},SUB-STORE`; + }; + return { type, func }; +} + +function SurgeRuleSet() { + const type = 'SINGLE'; + const func = (rule) => { + const UNSUPPORTED = ['GEOSITE', 'GEOIP']; + if (UNSUPPORTED.indexOf(rule.type) !== -1) return null; + let output = `${rule.type},${rule.content}`; + if (['IP-CIDR', 'IP-CIDR6'].includes(rule.type)) { + output += + rule.options?.length > 0 ? `,${rule.options.join(',')}` : ''; + } + return output; + }; + return { type, func }; +} + +function LoonRules() { + const type = 'SINGLE'; + const func = (rule) => { + // skip unsupported rules + const UNSUPPORTED = ['SRC-IP', 'GEOSITE', 'GEOIP']; + if (UNSUPPORTED.indexOf(rule.type) !== -1) return null; + if (['IP-CIDR', 'IP-CIDR6'].includes(rule.type) && rule.options) { + // Loon only supports the no-resolve option + rule.options = rule.options.filter((option) => + ['no-resolve'].includes(option), + ); + } + return SurgeRuleSet().func(rule); + }; + return { type, func }; +} + +function ClashRuleProvider() { + const type = 'ALL'; + const func = (rules) => { + const TRANSFORM = { + 'DEST-PORT': 'DST-PORT', + 'SRC-IP': 'SRC-IP-CIDR', + 'IN-PORT': 'SRC-PORT', + }; + const conf = { + payload: rules.map((rule) => { + let output = `${TRANSFORM[rule.type] || rule.type},${ + rule.content + }`; + if (['IP-CIDR', 'IP-CIDR6', 'GEOIP'].includes(rule.type)) { + if (rule.options) { + // Clash only supports the no-resolve option + rule.options = rule.options.filter((option) => + ['no-resolve'].includes(option), + ); + } + output += + rule.options?.length > 0 + ? `,${rule.options.join(',')}` + : ''; + } + return output; + }), + }; + return YAML.dump(conf); + }; + return { type, func }; +} + +export default { + QX: QXFilter(), + Surge: SurgeRuleSet(), + Loon: LoonRules(), + Clash: ClashRuleProvider(), +}; diff --git a/backend/src/main.js b/backend/src/main.js new file mode 100644 index 0000000000..594f6ec031 --- /dev/null +++ b/backend/src/main.js @@ -0,0 +1,26 @@ +/** + * ███████╗██╗ ██╗██████╗ ███████╗████████╗ ██████╗ ██████╗ ███████╗ + * ██╔════╝██║ ██║██╔══██╗ ██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗██╔════╝ + * ███████╗██║ ██║██████╔╝█████╗███████╗ ██║ ██║ ██║██████╔╝█████╗ + * ╚════██║██║ ██║██╔══██╗╚════╝╚════██║ ██║ ██║ ██║██╔══██╗██╔══╝ + * ███████║╚██████╔╝██████╔╝ ███████║ ██║ ╚██████╔╝██║ ██║███████╗ + * ╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ + * Advanced Subscription Manager for QX, Loon, Surge and Clash. + * @author: Peng-YM + * @github: https://github.com/sub-store-org/Sub-Store + * @documentation: https://www.notion.so/Sub-Store-6259586994d34c11a4ced5c406264b46 + */ +import { version } from '../package.json'; +import $ from '@/core/app'; +console.log( + ` +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ + Sub-Store -- v${version} +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ +`, +); +import migrate from '@/utils/migration'; +import serve from '@/restful'; + +migrate(); +serve(); diff --git a/backend/src/products/cron-sync-artifacts.js b/backend/src/products/cron-sync-artifacts.js new file mode 100644 index 0000000000..e1eac64847 --- /dev/null +++ b/backend/src/products/cron-sync-artifacts.js @@ -0,0 +1,250 @@ +import { version } from '../../package.json'; +import { + SETTINGS_KEY, + ARTIFACTS_KEY, + SUBS_KEY, + COLLECTIONS_KEY, +} from '@/constants'; +import $ from '@/core/app'; +import { produceArtifact } from '@/restful/sync'; +import { syncToGist } from '@/restful/artifacts'; +import { findByName } from '@/utils/database'; + +!(async function () { + let arg; + if (typeof $argument != 'undefined') { + arg = Object.fromEntries( + // eslint-disable-next-line no-undef + $argument.split('&').map((item) => item.split('=')), + ); + } else { + arg = {}; + } + let sub_names = (arg?.subscription ?? arg?.sub ?? '') + .split(/,|,/g) + .map((i) => i.trim()) + .filter((i) => i.length > 0) + .map((i) => decodeURIComponent(i)); + let col_names = (arg?.collection ?? arg?.col ?? '') + .split(/,|,/g) + .map((i) => i.trim()) + .filter((i) => i.length > 0) + .map((i) => decodeURIComponent(i)); + if (sub_names.length > 0 || col_names.length > 0) { + if (sub_names.length > 0) + await produceArtifacts(sub_names, 'subscription'); + if (col_names.length > 0) + await produceArtifacts(col_names, 'collection'); + } else { + const settings = $.read(SETTINGS_KEY); + // if GitHub token is not configured + if (!settings.githubUser || !settings.gistToken) return; + + const artifacts = $.read(ARTIFACTS_KEY); + if (!artifacts || artifacts.length === 0) return; + + const shouldSync = artifacts.some((artifact) => artifact.sync); + if (shouldSync) await doSync(); + } +})().finally(() => $.done()); + +async function produceArtifacts(names, type) { + try { + if (names.length > 0) { + $.info(`produceArtifacts ${type} 开始: ${names.join(', ')}`); + await Promise.all( + names.map(async (name) => { + try { + await produceArtifact({ + type, + name, + }); + } catch (e) { + $.error(`${type} ${name} error: ${e.message ?? e}`); + } + }), + ); + $.info(`produceArtifacts ${type} 完成: ${names.join(', ')}`); + } + } catch (e) { + $.error(`produceArtifacts error: ${e.message ?? e}`); + } +} +async function doSync() { + console.log( + ` +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ + Sub-Store Sync -- v${version} +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ +`, + ); + + $.info('开始同步所有远程配置...'); + const allArtifacts = $.read(ARTIFACTS_KEY); + const files = {}; + + try { + const valid = []; + const invalid = []; + const allSubs = $.read(SUBS_KEY); + const allCols = $.read(COLLECTIONS_KEY); + const subNames = []; + let enabledCount = 0; + allArtifacts.map((artifact) => { + if (artifact.sync && artifact.source) { + enabledCount++; + if (artifact.type === 'subscription') { + const subName = artifact.source; + const sub = findByName(allSubs, subName); + if (sub && sub.url && !subNames.includes(subName)) { + subNames.push(subName); + } + } else if (artifact.type === 'collection') { + const collection = findByName(allCols, artifact.source); + if (collection && Array.isArray(collection.subscriptions)) { + collection.subscriptions.map((subName) => { + const sub = findByName(allSubs, subName); + if (sub && sub.url && !subNames.includes(subName)) { + subNames.push(subName); + } + }); + } + } + } + }); + + if (enabledCount === 0) { + $.info( + `需同步的配置: ${enabledCount}, 总数: ${allArtifacts.length}`, + ); + return; + } + + if (subNames.length > 0) { + await Promise.all( + subNames.map(async (subName) => { + try { + await produceArtifact({ + type: 'subscription', + name: subName, + awaitCustomCache: true, + }); + } catch (e) { + // $.error(`${e.message ?? e}`); + } + }), + ); + } + await Promise.all( + allArtifacts.map(async (artifact) => { + try { + if (artifact.sync && artifact.source) { + $.info(`正在同步云配置:${artifact.name}...`); + + const useMihomoExternal = + artifact.platform === 'SurgeMac'; + + if (useMihomoExternal) { + $.info( + `手动指定了 target 为 SurgeMac, 将使用 Mihomo External`, + ); + } + const output = await produceArtifact({ + type: artifact.type, + name: artifact.source, + platform: artifact.platform, + produceOpts: { + 'include-unsupported-proxy': + artifact.includeUnsupportedProxy, + useMihomoExternal, + }, + }); + + // if (!output || output.length === 0) + // throw new Error('该配置的结果为空 不进行上传'); + + files[encodeURIComponent(artifact.name)] = { + content: output, + }; + + valid.push(artifact.name); + } + } catch (e) { + $.error( + `生成同步配置 ${artifact.name} 发生错误: ${ + e.message ?? e + }`, + ); + invalid.push(artifact.name); + } + }), + ); + + $.info(`${valid.length} 个同步配置生成成功: ${valid.join(', ')}`); + $.info(`${invalid.length} 个同步配置生成失败: ${invalid.join(', ')}`); + + if (valid.length === 0) { + throw new Error( + `同步配置 ${invalid.join(', ')} 生成失败 详情请查看日志`, + ); + } + + const resp = await syncToGist(files); + const body = JSON.parse(resp.body); + delete body.history; + delete body.forks; + delete body.owner; + Object.values(body.files).forEach((file) => { + delete file.content; + }); + $.info('上传配置响应:'); + $.info(JSON.stringify(body, null, 2)); + + for (const artifact of allArtifacts) { + if ( + artifact.sync && + artifact.source && + valid.includes(artifact.name) + ) { + artifact.updated = new Date().getTime(); + // extract real url from gist + let files = body.files; + let isGitLab; + if (Array.isArray(files)) { + isGitLab = true; + files = Object.fromEntries( + files.map((item) => [item.path, item]), + ); + } + const raw_url = + files[encodeURIComponent(artifact.name)]?.raw_url; + const new_url = isGitLab + ? raw_url + : raw_url?.replace(/\/raw\/[^/]*\/(.*)/, '/raw/$1'); + $.info( + `上传配置完成\n文件列表: ${Object.keys(files).join( + ', ', + )}\n当前文件: ${encodeURIComponent( + artifact.name, + )}\n响应返回的原始链接: ${raw_url}\n处理完的新链接: ${new_url}`, + ); + artifact.url = new_url; + } + } + + $.write(allArtifacts, ARTIFACTS_KEY); + $.info('上传配置成功'); + + if (invalid.length > 0) { + $.notify( + '🌍 Sub-Store', + `同步配置成功 ${valid.length} 个, 失败 ${invalid.length} 个, 详情请查看日志`, + ); + } else { + $.notify('🌍 Sub-Store', '同步配置完成'); + } + } catch (e) { + $.notify('🌍 Sub-Store', '同步配置失败', `原因:${e.message ?? e}`); + $.error(`无法同步配置到 Gist,原因:${e}`); + } +} diff --git a/backend/src/products/resource-parser.loon.js b/backend/src/products/resource-parser.loon.js new file mode 100644 index 0000000000..c5de8675de --- /dev/null +++ b/backend/src/products/resource-parser.loon.js @@ -0,0 +1,103 @@ +/* eslint-disable no-undef */ +import { ProxyUtils } from '@/core/proxy-utils'; +import { RuleUtils } from '@/core/rule-utils'; +import { version } from '../../package.json'; +import download from '@/utils/download'; + +let result = ''; +let resource = typeof $resource !== 'undefined' ? $resource : ''; +let resourceType = typeof $resourceType !== 'undefined' ? $resourceType : ''; +let resourceUrl = typeof $resourceUrl !== 'undefined' ? $resourceUrl : ''; + +!(async () => { + console.log( + ` + ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ + Sub-Store -- v${version} + Loon -- ${$loon} + ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ + `, + ); + + const build = $loon.match(/\((\d+)\)$/)?.[1]; + let arg; + if (typeof $argument != 'undefined') { + arg = Object.fromEntries( + $argument.split('&').map((item) => item.split('=')), + ); + } else { + arg = {}; + } + console.log(`arg: ${JSON.stringify(arg)}`); + + const RESOURCE_TYPE = { + PROXY: 1, + RULE: 2, + }; + if (!arg.resourceUrlOnly) { + result = resource; + } + + if (resourceType === RESOURCE_TYPE.PROXY) { + if (!arg.resourceUrlOnly) { + try { + let proxies = ProxyUtils.parse(resource); + result = ProxyUtils.produce(proxies, 'Loon', undefined, { + 'include-unsupported-proxy': + arg?.includeUnsupportedProxy || build >= 842, + }); + } catch (e) { + console.log('解析器: 使用 resource 出现错误'); + console.log(e.message ?? e); + } + } + if ((!result || /^\s*$/.test(result)) && resourceUrl) { + console.log(`解析器: 尝试从 ${resourceUrl} 获取订阅`); + try { + let raw = await download( + resourceUrl, + arg?.ua, + arg?.timeout, + undefined, + undefined, + undefined, + undefined, + true, + ); + let proxies = ProxyUtils.parse(raw); + result = ProxyUtils.produce(proxies, 'Loon', undefined, { + 'include-unsupported-proxy': + arg?.includeUnsupportedProxy || build >= 842, + }); + } catch (e) { + console.log(e.message ?? e); + } + } + } else if (resourceType === RESOURCE_TYPE.RULE) { + if (!arg.resourceUrlOnly) { + try { + const rules = RuleUtils.parse(resource); + result = RuleUtils.produce(rules, 'Loon'); + } catch (e) { + console.log(e.message ?? e); + } + } + if ((!result || /^\s*$/.test(result)) && resourceUrl) { + console.log(`解析器: 尝试从 ${resourceUrl} 获取规则`); + try { + let raw = await download(resourceUrl, arg?.ua, arg?.timeout); + let rules = RuleUtils.parse(raw); + result = RuleUtils.produce(rules, 'Loon'); + } catch (e) { + console.log(e.message ?? e); + } + } + } +})() + .catch(async (e) => { + console.log('解析器: 出现错误'); + console.log(e.message ?? e); + }) + .finally(() => { + $done(result || ''); + }); diff --git a/backend/src/products/sub-store-0.js b/backend/src/products/sub-store-0.js new file mode 100644 index 0000000000..04bc160a91 --- /dev/null +++ b/backend/src/products/sub-store-0.js @@ -0,0 +1,45 @@ +/** + * 路由拆分 - 本文件只包含不涉及到解析器的 RESTFul API + */ + +import { version } from '../../package.json'; +console.log( + ` +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ + Sub-Store -- v${version} +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ +`, +); + +import migrate from '@/utils/migration'; +import express from '@/vendor/express'; +import $ from '@/core/app'; +import registerCollectionRoutes from '@/restful/collections'; +import registerSubscriptionRoutes from '@/restful/subscriptions'; +import registerArtifactRoutes from '@/restful/artifacts'; +import registerSettingRoutes from '@/restful/settings'; +import registerMiscRoutes from '@/restful/miscs'; +import registerSortRoutes from '@/restful/sort'; +import registerFileRoutes from '@/restful/file'; +import registerTokenRoutes from '@/restful/token'; +import registerModuleRoutes from '@/restful/module'; + +migrate(); +serve(); + +function serve() { + const $app = express({ substore: $ }); + + // register routes + registerCollectionRoutes($app); + registerSubscriptionRoutes($app); + registerTokenRoutes($app); + registerFileRoutes($app); + registerModuleRoutes($app); + registerArtifactRoutes($app); + registerSettingRoutes($app); + registerSortRoutes($app); + registerMiscRoutes($app); + + $app.start(); +} diff --git a/backend/src/products/sub-store-1.js b/backend/src/products/sub-store-1.js new file mode 100644 index 0000000000..1a17b8ec88 --- /dev/null +++ b/backend/src/products/sub-store-1.js @@ -0,0 +1,39 @@ +/** + * 路由拆分 - 本文件仅包含使用到解析器的 RESTFul API + */ + +import { version } from '../../package.json'; +import migrate from '@/utils/migration'; +import express from '@/vendor/express'; +import $ from '@/core/app'; +import registerDownloadRoutes from '@/restful/download'; +import registerPreviewRoutes from '@/restful/preview'; +import registerSyncRoutes from '@/restful/sync'; +import registerNodeInfoRoutes from '@/restful/node-info'; + +console.log( + ` +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ + Sub-Store -- v${version} +┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ +`, +); + +migrate(); +serve(); + +function serve() { + const $app = express({ substore: $ }); + + // register routes + registerDownloadRoutes($app); + registerPreviewRoutes($app); + registerSyncRoutes($app); + registerNodeInfoRoutes($app); + + $app.options('/', (req, res) => { + res.status(200).end(); + }); + + $app.start(); +} diff --git a/backend/src/restful/artifacts.js b/backend/src/restful/artifacts.js new file mode 100644 index 0000000000..e4626a382a --- /dev/null +++ b/backend/src/restful/artifacts.js @@ -0,0 +1,277 @@ +import $ from '@/core/app'; + +import { + ARTIFACT_REPOSITORY_KEY, + ARTIFACTS_KEY, + SETTINGS_KEY, +} from '@/constants'; +import { deleteByName, findByName, updateByName } from '@/utils/database'; +import { failed, success } from '@/restful/response'; +import { + InternalServerError, + RequestInvalidError, + ResourceNotFoundError, +} from '@/restful/errors'; +import Gist from '@/utils/gist'; + +export default function register($app) { + // Initialization + if (!$.read(ARTIFACTS_KEY)) $.write({}, ARTIFACTS_KEY); + + // RESTful APIs + $app.get('/api/artifacts/restore', restoreArtifacts); + + $app.route('/api/artifacts') + .get(getAllArtifacts) + .post(createArtifact) + .put(replaceArtifact); + + $app.route('/api/artifact/:name') + .get(getArtifact) + .patch(updateArtifact) + .delete(deleteArtifact); +} + +async function restoreArtifacts(_, res) { + $.info('开始恢复远程配置...'); + try { + const { gistToken, syncPlatform } = $.read(SETTINGS_KEY); + if (!gistToken) { + return Promise.reject('未设置 GitHub Token!'); + } + const manager = new Gist({ + token: gistToken, + key: ARTIFACT_REPOSITORY_KEY, + syncPlatform, + }); + + try { + const gist = await manager.locate(); + if (!gist?.files) { + throw new Error(`找不到 Sub-Store Gist 文件列表`); + } + const allArtifacts = $.read(ARTIFACTS_KEY); + const failed = []; + Object.keys(gist.files).map((key) => { + const filename = gist.files[key]?.filename; + if (filename) { + if (encodeURIComponent(filename) !== filename) { + $.error(`文件名 ${filename} 未编码 不保存`); + failed.push(filename); + } else { + const artifact = findByName(allArtifacts, filename); + if (artifact) { + updateByName(allArtifacts, filename, { + ...artifact, + url: gist.files[key]?.raw_url.replace( + /\/raw\/[^/]*\/(.*)/, + '/raw/$1', + ), + }); + } else { + allArtifacts.push({ + name: `${filename}`, + url: gist.files[key]?.raw_url.replace( + /\/raw\/[^/]*\/(.*)/, + '/raw/$1', + ), + }); + } + } + } + }); + $.write(allArtifacts, ARTIFACTS_KEY); + } catch (err) { + $.error(`查找 Sub-Store Gist 时发生错误: ${err.message ?? err}`); + throw err; + } + success(res); + } catch (e) { + $.error(`恢复远程配置失败,原因:${e.message ?? e}`); + failed( + res, + new InternalServerError( + `FAILED_TO_RESTORE_ARTIFACTS`, + `Failed to restore artifacts`, + `Reason: ${e.message ?? e}`, + ), + ); + } +} + +function getAllArtifacts(req, res) { + const allArtifacts = $.read(ARTIFACTS_KEY); + success(res, allArtifacts); +} + +function replaceArtifact(req, res) { + const allArtifacts = req.body; + $.write(allArtifacts, ARTIFACTS_KEY); + success(res); +} + +async function getArtifact(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + const allArtifacts = $.read(ARTIFACTS_KEY); + const artifact = findByName(allArtifacts, name); + + if (artifact) { + success(res, artifact); + } else { + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `Artifact ${name} does not exist!`, + ), + 404, + ); + } +} + +function createArtifact(req, res) { + const artifact = req.body; + if (!validateArtifactName(artifact.name)) { + failed( + res, + new RequestInvalidError( + 'INVALID_ARTIFACT_NAME', + `Artifact name ${artifact.name} is invalid.`, + ), + ); + return; + } + + $.info(`正在创建远程配置:${artifact.name}`); + const allArtifacts = $.read(ARTIFACTS_KEY); + if (findByName(allArtifacts, artifact.name)) { + failed( + res, + new RequestInvalidError( + 'DUPLICATE_KEY', + `Artifact ${artifact.name} already exists.`, + ), + ); + } else { + allArtifacts.push(artifact); + $.write(allArtifacts, ARTIFACTS_KEY); + success(res, artifact, 201); + } +} + +function updateArtifact(req, res) { + const allArtifacts = $.read(ARTIFACTS_KEY); + let oldName = req.params.name; + oldName = decodeURIComponent(oldName); + const artifact = findByName(allArtifacts, oldName); + if (artifact) { + $.info(`正在更新远程配置:${artifact.name}`); + const newArtifact = { + ...artifact, + ...req.body, + }; + if (!validateArtifactName(newArtifact.name)) { + failed( + res, + new RequestInvalidError( + 'INVALID_ARTIFACT_NAME', + `Artifact name ${newArtifact.name} is invalid.`, + ), + ); + return; + } + updateByName(allArtifacts, oldName, newArtifact); + $.write(allArtifacts, ARTIFACTS_KEY); + success(res, newArtifact); + } else { + failed( + res, + new RequestInvalidError( + 'DUPLICATE_KEY', + `Artifact ${oldName} already exists.`, + ), + ); + } +} + +async function deleteArtifact(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + $.info(`正在删除远程配置:${name}`); + const allArtifacts = $.read(ARTIFACTS_KEY); + try { + const artifact = findByName(allArtifacts, name); + if (!artifact) throw new Error(`远程配置:${name}不存在!`); + if (artifact.updated) { + // delete gist + const files = {}; + files[encodeURIComponent(artifact.name)] = { + content: '', + }; + if (encodeURIComponent(artifact.name) !== artifact.name) { + files[artifact.name] = { + content: '', + }; + } + + // 当别的Sub 删了同步订阅 或 gist里面删了 当前设备没有删除 时 无法删除的bug + try { + await syncToGist(files); + } catch (i) { + $.error(`Function syncToGist: ${name} : ${i}`); + } + } + // delete local cache + deleteByName(allArtifacts, name); + $.write(allArtifacts, ARTIFACTS_KEY); + success(res); + } catch (err) { + $.error(`无法删除远程配置:${name},原因:${err}`); + failed( + res, + new InternalServerError( + `FAILED_TO_DELETE_ARTIFACT`, + `Failed to delete artifact ${name}`, + `Reason: ${err}`, + ), + ); + } +} + +function validateArtifactName(name) { + return /^[a-zA-Z0-9._-]*$/.test(name); +} + +async function syncToGist(files) { + const { gistToken, syncPlatform } = $.read(SETTINGS_KEY); + if (!gistToken) { + return Promise.reject('未设置 GitHub Token!'); + } + const manager = new Gist({ + token: gistToken, + key: ARTIFACT_REPOSITORY_KEY, + syncPlatform, + }); + const res = await manager.upload(files); + let body = {}; + try { + body = JSON.parse(res.body); + // eslint-disable-next-line no-empty + } catch (e) {} + + const url = body?.html_url ?? body?.web_url; + const settings = $.read(SETTINGS_KEY); + if (url) { + $.log(`同步 Gist 后, 找到 Sub-Store Gist: ${url}`); + settings.artifactStore = url; + settings.artifactStoreStatus = 'VALID'; + } else { + $.error(`同步 Gist 后, 找不到 Sub-Store Gist`); + settings.artifactStoreStatus = 'NOT FOUND'; + } + $.write(settings, SETTINGS_KEY); + return res; +} + +export { syncToGist }; diff --git a/backend/src/restful/collections.js b/backend/src/restful/collections.js new file mode 100644 index 0000000000..116998439c --- /dev/null +++ b/backend/src/restful/collections.js @@ -0,0 +1,157 @@ +import { deleteByName, findByName, updateByName } from '@/utils/database'; +import { COLLECTIONS_KEY, ARTIFACTS_KEY, FILES_KEY } from '@/constants'; +import { failed, success } from '@/restful/response'; +import $ from '@/core/app'; +import { RequestInvalidError, ResourceNotFoundError } from '@/restful/errors'; +import { formatDateTime } from '@/utils'; + +export default function register($app) { + if (!$.read(COLLECTIONS_KEY)) $.write({}, COLLECTIONS_KEY); + + $app.route('/api/collection/:name') + .get(getCollection) + .patch(updateCollection) + .delete(deleteCollection); + + $app.route('/api/collections') + .get(getAllCollections) + .post(createCollection) + .put(replaceCollection); +} + +// collection API +function createCollection(req, res) { + const collection = req.body; + $.info(`正在创建组合订阅:${collection.name}`); + if (/\//.test(collection.name)) { + failed( + res, + new RequestInvalidError( + 'INVALID_NAME', + `Collection ${collection.name} is invalid`, + ), + ); + return; + } + const allCols = $.read(COLLECTIONS_KEY); + if (findByName(allCols, collection.name)) { + failed( + res, + new RequestInvalidError( + 'DUPLICATE_KEY', + `Collection ${collection.name} already exists.`, + ), + ); + return; + } + allCols.push(collection); + $.write(allCols, COLLECTIONS_KEY); + success(res, collection, 201); +} + +function getCollection(req, res) { + let { name } = req.params; + let { raw } = req.query; + name = decodeURIComponent(name); + const allCols = $.read(COLLECTIONS_KEY); + const collection = findByName(allCols, name); + if (collection) { + if (raw) { + res.set('content-type', 'application/json') + .set( + 'content-disposition', + `attachment; filename="${encodeURIComponent( + `sub-store_collection_${name}_${formatDateTime( + new Date(), + )}.json`, + )}"`, + ) + .send(JSON.stringify(collection)); + } else { + success(res, collection); + } + } else { + failed( + res, + new ResourceNotFoundError( + `SUBSCRIPTION_NOT_FOUND`, + `Collection ${name} does not exist`, + 404, + ), + ); + } +} + +function updateCollection(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + let collection = req.body; + const allCols = $.read(COLLECTIONS_KEY); + const oldCol = findByName(allCols, name); + if (oldCol) { + const newCol = { + ...oldCol, + ...collection, + }; + $.info(`正在更新组合订阅:${name}...`); + + if (name !== newCol.name) { + // update all artifacts referring this collection + const allArtifacts = $.read(ARTIFACTS_KEY) || []; + for (const artifact of allArtifacts) { + if ( + artifact.type === 'collection' && + artifact.source === oldCol.name + ) { + artifact.source = newCol.name; + } + } + // update all files referring this collection + const allFiles = $.read(FILES_KEY) || []; + for (const file of allFiles) { + if ( + file.sourceType === 'collection' && + file.sourceName === oldCol.name + ) { + file.sourceName = newCol.name; + } + } + $.write(allArtifacts, ARTIFACTS_KEY); + $.write(allFiles, FILES_KEY); + } + + updateByName(allCols, name, newCol); + $.write(allCols, COLLECTIONS_KEY); + success(res, newCol); + } else { + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `Collection ${name} does not exist!`, + ), + 404, + ); + } +} + +function deleteCollection(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + $.info(`正在删除组合订阅:${name}`); + let allCols = $.read(COLLECTIONS_KEY); + deleteByName(allCols, name); + $.write(allCols, COLLECTIONS_KEY); + success(res); +} + +function getAllCollections(req, res) { + const allCols = $.read(COLLECTIONS_KEY); + success(res, allCols); +} + +function replaceCollection(req, res) { + const allCols = req.body; + $.write(allCols, COLLECTIONS_KEY); + success(res); +} diff --git a/backend/src/restful/download.js b/backend/src/restful/download.js new file mode 100644 index 0000000000..bea243fd5d --- /dev/null +++ b/backend/src/restful/download.js @@ -0,0 +1,778 @@ +import { + getPlatformFromHeaders, + shouldIncludeUnsupportedProxy, +} from '@/utils/user-agent'; +import { ProxyUtils } from '@/core/proxy-utils'; +import { COLLECTIONS_KEY, SUBS_KEY } from '@/constants'; +import { findByName } from '@/utils/database'; +import { getFlowHeaders, normalizeFlowHeader } from '@/utils/flow'; +import $ from '@/core/app'; +import { failed } from '@/restful/response'; +import { InternalServerError, ResourceNotFoundError } from '@/restful/errors'; +import { produceArtifact } from '@/restful/sync'; +// eslint-disable-next-line no-unused-vars +import { isIPv4, isIPv6 } from '@/utils'; +import { getISO } from '@/utils/geo'; +import env from '@/utils/env'; + +export default function register($app) { + $app.get('/share/col/:name/:target', async (req, res) => { + const { target } = req.params; + if (target) { + req.query.target = target; + $.info(`使用路由指定目标: ${target}`); + } + await downloadCollection(req, res); + }); + $app.get('/share/col/:name', downloadCollection); + $app.get('/share/sub/:name/:target', async (req, res) => { + const { target } = req.params; + if (target) { + req.query.target = target; + $.info(`使用路由指定目标: ${target}`); + } + await downloadSubscription(req, res); + }); + $app.get('/share/sub/:name', downloadSubscription); + + $app.get('/download/collection/:name/:target', async (req, res) => { + const { target } = req.params; + if (target) { + req.query.target = target; + $.info(`使用路由指定目标: ${target}`); + } + await downloadCollection(req, res); + }); + $app.get('/download/collection/:name', downloadCollection); + $app.get('/download/:name/:target', async (req, res) => { + const { target } = req.params; + if (target) { + req.query.target = target; + $.info(`使用路由指定目标: ${target}`); + } + await downloadSubscription(req, res); + }); + $app.get('/download/:name', downloadSubscription); + + $app.get( + '/download/collection/:name/api/v1/server/details', + async (req, res) => { + req.query.platform = 'JSON'; + req.query.produceType = 'internal'; + req.query.resultFormat = 'nezha'; + await downloadCollection(req, res); + }, + ); + $app.get('/download/:name/api/v1/server/details', async (req, res) => { + req.query.platform = 'JSON'; + req.query.produceType = 'internal'; + req.query.resultFormat = 'nezha'; + await downloadSubscription(req, res); + }); + $app.get( + '/download/collection/:name/api/v1/monitor/:nezhaIndex', + async (req, res) => { + req.query.platform = 'JSON'; + req.query.produceType = 'internal'; + req.query.resultFormat = 'nezha-monitor'; + await downloadCollection(req, res); + }, + ); + $app.get('/download/:name/api/v1/monitor/:nezhaIndex', async (req, res) => { + req.query.platform = 'JSON'; + req.query.produceType = 'internal'; + req.query.resultFormat = 'nezha-monitor'; + await downloadSubscription(req, res); + }); +} + +async function downloadSubscription(req, res) { + let { name, nezhaIndex } = req.params; + name = decodeURIComponent(name); + nezhaIndex = decodeURIComponent(nezhaIndex); + + const useMihomoExternal = req.query.target === 'SurgeMac'; + + const platform = + req.query.target || getPlatformFromHeaders(req.headers) || 'JSON'; + const reqUA = req.headers['user-agent'] || req.headers['User-Agent']; + $.info( + `正在下载订阅:${name}\n请求 User-Agent: ${reqUA}\n请求 target: ${req.query.target}\n实际输出: ${platform}`, + ); + let { + url, + ua, + content, + mergeSources, + ignoreFailedRemoteSub, + produceType, + includeUnsupportedProxy, + resultFormat, + proxy, + noCache, + } = req.query; + let $options = { + _req: { + method: req.method, + url: req.url, + path: req.path, + query: req.query, + params: req.params, + headers: req.headers, + body: req.body, + }, + }; + if (req.query.$options) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $options = JSON.parse(decodeURIComponent(req.query.$options)); + } catch (e) { + for (const pair of req.query.$options.split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $options[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + $.info(`传入 $options: ${JSON.stringify($options)}`); + } + if (url) { + url = decodeURIComponent(url); + $.info(`指定远程订阅 URL: ${url}`); + if (!/^https?:\/\//.test(url)) { + content = url; + $.info(`URL 不是链接,视为本地订阅`); + } + } + if (content) { + content = decodeURIComponent(content); + $.info(`指定本地订阅: ${content}`); + } + if (proxy) { + proxy = decodeURIComponent(proxy); + $.info(`指定远程订阅使用代理/策略 proxy: ${proxy}`); + } + if (ua) { + ua = decodeURIComponent(ua); + $.info(`指定远程订阅 User-Agent: ${ua}`); + } + + if (mergeSources) { + mergeSources = decodeURIComponent(mergeSources); + $.info(`指定合并来源: ${mergeSources}`); + } + if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') { + ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub); + $.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`); + } + if (produceType) { + produceType = decodeURIComponent(produceType); + $.info(`指定生产类型: ${produceType}`); + } + if (includeUnsupportedProxy) { + includeUnsupportedProxy = decodeURIComponent(includeUnsupportedProxy); + $.info( + `包含官方/商店版/未续费订阅不支持的协议: ${includeUnsupportedProxy}`, + ); + } + + if ( + !includeUnsupportedProxy && + shouldIncludeUnsupportedProxy(platform, reqUA) + ) { + includeUnsupportedProxy = true; + $.info( + `当前客户端可包含官方/商店版/未续费订阅不支持的协议: ${includeUnsupportedProxy}`, + ); + } + + if (useMihomoExternal) { + $.info(`手动指定了 target 为 SurgeMac, 将使用 Mihomo External`); + } + + if (noCache) { + $.info(`指定不使用缓存: ${noCache}`); + } + + const allSubs = $.read(SUBS_KEY); + const sub = findByName(allSubs, name); + if (sub) { + try { + const passThroughUA = sub.passThroughUA; + if (passThroughUA) { + $.info( + `订阅开启了透传 User-Agent, 使用请求的 User-Agent: ${reqUA}`, + ); + ua = reqUA; + } + let output = await produceArtifact({ + type: 'subscription', + name, + platform, + url, + ua, + content, + mergeSources, + ignoreFailedRemoteSub, + produceType, + produceOpts: { + 'include-unsupported-proxy': includeUnsupportedProxy, + useMihomoExternal, + }, + $options, + proxy, + noCache, + }); + let flowInfo; + if ( + sub.source !== 'local' || + ['localFirst', 'remoteFirst'].includes(sub.mergeSources) + ) { + try { + url = + `${url || sub.url}` + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length)?.[0] || ''; + + let $arguments = {}; + const rawArgs = url.split('#'); + url = url.split('#')[0]; + if (rawArgs.length > 1) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $arguments = JSON.parse( + decodeURIComponent(rawArgs[1]), + ); + } catch (e) { + for (const pair of rawArgs[1].split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $arguments[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + } + if (!$arguments.noFlow) { + // forward flow headers + flowInfo = await getFlowHeaders( + $arguments?.insecure ? `${url}#insecure` : url, + $arguments.flowUserAgent, + undefined, + proxy || sub.proxy, + $arguments.flowUrl, + ); + if (flowInfo) { + res.set( + 'subscription-userinfo', + normalizeFlowHeader(flowInfo), + ); + } + } + } catch (err) { + $.error( + `订阅 ${name} 获取流量信息时发生错误: ${JSON.stringify( + err, + )}`, + ); + } + } + if (sub.subUserinfo) { + let subUserInfo; + if (/^https?:\/\//.test(sub.subUserinfo)) { + try { + subUserInfo = await getFlowHeaders( + undefined, + undefined, + undefined, + proxy || sub.proxy, + sub.subUserinfo, + ); + } catch (e) { + $.error( + `订阅 ${name} 使用自定义流量链接 ${ + sub.subUserinfo + } 获取流量信息时发生错误: ${JSON.stringify(e)}`, + ); + } + } else { + subUserInfo = sub.subUserinfo; + } + res.set( + 'subscription-userinfo', + normalizeFlowHeader( + [subUserInfo, flowInfo].filter((i) => i).join(';'), + ), + ); + } + + if (platform === 'JSON') { + if (resultFormat === 'nezha') { + output = nezhaTransform(output); + } else if (resultFormat === 'nezha-monitor') { + nezhaIndex = /^\d+$/.test(nezhaIndex) + ? parseInt(nezhaIndex, 10) + : output.findIndex((i) => i.name === nezhaIndex); + output = await nezhaMonitor( + output[nezhaIndex], + nezhaIndex, + req.query, + ); + } + res.set('Content-Type', 'application/json;charset=utf-8').send( + output, + ); + } else { + res.send(output); + } + } catch (err) { + $.notify( + `🌍 Sub-Store 下载订阅失败`, + `❌ 无法下载订阅:${name}!`, + `🤔 原因:${err.message ?? err}`, + ); + $.error(err.message ?? err); + failed( + res, + new InternalServerError( + 'INTERNAL_SERVER_ERROR', + `Failed to download subscription: ${name}`, + `Reason: ${err.message ?? err}`, + ), + ); + } + } else { + $.error(`🌍 Sub-Store 下载订阅失败\n❌ 未找到订阅:${name}!`); + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `Subscription ${name} does not exist!`, + ), + 404, + ); + } +} + +async function downloadCollection(req, res) { + let { name, nezhaIndex } = req.params; + name = decodeURIComponent(name); + nezhaIndex = decodeURIComponent(nezhaIndex); + + const useMihomoExternal = req.query.target === 'SurgeMac'; + + const platform = + req.query.target || getPlatformFromHeaders(req.headers) || 'JSON'; + + const allCols = $.read(COLLECTIONS_KEY); + const collection = findByName(allCols, name); + const reqUA = req.headers['user-agent'] || req.headers['User-Agent']; + $.info( + `正在下载组合订阅:${name}\n请求 User-Agent: ${reqUA}\n请求 target: ${req.query.target}\n实际输出: ${platform}`, + ); + + let { + ignoreFailedRemoteSub, + produceType, + includeUnsupportedProxy, + resultFormat, + proxy, + noCache, + } = req.query; + + let $options = { + _req: { + method: req.method, + url: req.url, + path: req.path, + query: req.query, + params: req.params, + headers: req.headers, + body: req.body, + }, + }; + if (req.query.$options) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $options = JSON.parse(decodeURIComponent(req.query.$options)); + } catch (e) { + for (const pair of req.query.$options.split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $options[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + $.info(`传入 $options: ${JSON.stringify($options)}`); + } + + if (proxy) { + proxy = decodeURIComponent(proxy); + $.info(`指定远程订阅使用代理/策略 proxy: ${proxy}`); + } + + if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') { + ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub); + $.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`); + } + if (produceType) { + produceType = decodeURIComponent(produceType); + $.info(`指定生产类型: ${produceType}`); + } + + if (includeUnsupportedProxy) { + includeUnsupportedProxy = decodeURIComponent(includeUnsupportedProxy); + $.info( + `包含官方/商店版/未续费订阅不支持的协议: ${includeUnsupportedProxy}`, + ); + } + if ( + !includeUnsupportedProxy && + shouldIncludeUnsupportedProxy(platform, reqUA) + ) { + includeUnsupportedProxy = true; + $.info( + `当前客户端可包含官方/商店版/未续费订阅不支持的协议: ${includeUnsupportedProxy}`, + ); + } + if (useMihomoExternal) { + $.info(`手动指定了 target 为 SurgeMac, 将使用 Mihomo External`); + } + if (noCache) { + $.info(`指定不使用缓存: ${noCache}`); + } + + if (collection) { + try { + let output = await produceArtifact({ + type: 'collection', + name, + platform, + ignoreFailedRemoteSub, + produceType, + produceOpts: { + 'include-unsupported-proxy': includeUnsupportedProxy, + useMihomoExternal, + }, + $options, + proxy, + noCache, + ua: reqUA, + }); + let subUserInfoOfSub; + // forward flow header from the first subscription in this collection + const allSubs = $.read(SUBS_KEY); + const subnames = collection.subscriptions; + if (subnames.length > 0) { + const sub = findByName(allSubs, subnames[0]); + if ( + sub.source !== 'local' || + ['localFirst', 'remoteFirst'].includes(sub.mergeSources) + ) { + try { + let url = + `${sub.url}` + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length)?.[0] || ''; + + let $arguments = {}; + const rawArgs = url.split('#'); + url = url.split('#')[0]; + if (rawArgs.length > 1) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $arguments = JSON.parse( + decodeURIComponent(rawArgs[1]), + ); + } catch (e) { + for (const pair of rawArgs[1].split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $arguments[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + } + if (!$arguments.noFlow) { + subUserInfoOfSub = await getFlowHeaders( + $arguments?.insecure ? `${url}#insecure` : url, + $arguments.flowUserAgent, + undefined, + proxy || sub.proxy || collection.proxy, + $arguments.flowUrl, + ); + } + } catch (err) { + $.error( + `组合订阅 ${name} 中的子订阅 ${ + sub.name + } 获取流量信息时发生错误: ${err.message ?? err}`, + ); + } + } + if (sub.subUserinfo) { + let subUserInfo; + if (/^https?:\/\//.test(sub.subUserinfo)) { + try { + subUserInfo = await getFlowHeaders( + undefined, + undefined, + undefined, + proxy || sub.proxy, + sub.subUserinfo, + ); + } catch (e) { + $.error( + `组合订阅 ${name} 使用自定义流量链接 ${ + sub.subUserinfo + } 获取流量信息时发生错误: ${JSON.stringify(e)}`, + ); + } + } else { + subUserInfo = sub.subUserinfo; + } + subUserInfoOfSub = [subUserInfo, subUserInfoOfSub] + .filter((i) => i) + .join('; '); + } + } + + $.info(`组合订阅 ${name} 透传的的流量信息: ${subUserInfoOfSub}`); + + let subUserInfoOfCol; + if (/^https?:\/\//.test(collection.subUserinfo)) { + try { + subUserInfoOfCol = await getFlowHeaders( + undefined, + undefined, + undefined, + proxy || collection.proxy, + collection.subUserinfo, + ); + } catch (e) { + $.error( + `组合订阅 ${name} 使用自定义流量链接 ${ + collection.subUserinfo + } 获取流量信息时发生错误: ${JSON.stringify(e)}`, + ); + } + } else { + subUserInfoOfCol = collection.subUserinfo; + } + const subUserInfo = [subUserInfoOfCol, subUserInfoOfSub] + .filter((i) => i) + .join('; '); + if (subUserInfo) { + res.set( + 'subscription-userinfo', + normalizeFlowHeader(subUserInfo), + ); + } + if (platform === 'JSON') { + if (resultFormat === 'nezha') { + output = nezhaTransform(output); + } else if (resultFormat === 'nezha-monitor') { + nezhaIndex = /^\d+$/.test(nezhaIndex) + ? parseInt(nezhaIndex, 10) + : output.findIndex((i) => i.name === nezhaIndex); + output = await nezhaMonitor( + output[nezhaIndex], + nezhaIndex, + req.query, + ); + } + res.set('Content-Type', 'application/json;charset=utf-8').send( + output, + ); + } else { + res.send(output); + } + } catch (err) { + $.notify( + `🌍 Sub-Store 下载组合订阅失败`, + `❌ 下载组合订阅错误:${name}!`, + `🤔 原因:${err}`, + ); + failed( + res, + new InternalServerError( + 'INTERNAL_SERVER_ERROR', + `Failed to download collection: ${name}`, + `Reason: ${err.message ?? err}`, + ), + ); + } + } else { + $.error( + `🌍 Sub-Store 下载组合订阅失败`, + `❌ 未找到组合订阅:${name}!`, + ); + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `Collection ${name} does not exist!`, + ), + 404, + ); + } +} + +async function nezhaMonitor(proxy, index, query) { + const result = { + code: 0, + message: 'success', + result: [], + }; + + try { + const { isLoon, isSurge } = $.env; + if (!isLoon && !isSurge) + throw new Error('仅支持 Loon 和 Surge(ability=http-client-policy)'); + const node = ProxyUtils.produce([proxy], isLoon ? 'Loon' : 'Surge'); + if (!node) throw new Error('当前客户端不兼容此节点'); + const monitors = proxy._monitors || [ + { + name: 'Cloudflare', + url: 'http://cp.cloudflare.com/generate_204', + method: 'HEAD', + number: 3, + timeout: 2000, + }, + { + name: 'Google', + url: 'http://www.google.com/generate_204', + method: 'HEAD', + number: 3, + timeout: 2000, + }, + ]; + const number = + query.number || Math.max(...monitors.map((i) => i.number)) || 3; + for (const monitor of monitors) { + const interval = 10 * 60 * 1000; + const data = { + monitor_id: monitors.indexOf(monitor), + server_id: index, + monitor_name: monitor.name, + server_name: proxy.name, + created_at: [], + avg_delay: [], + }; + for (let index = 0; index < number; index++) { + const startedAt = Date.now(); + try { + await $.http[(monitor.method || 'HEAD').toLowerCase()]({ + timeout: monitor.timeout || 2000, + url: monitor.url, + 'policy-descriptor': node, + node, + }); + const latency = Date.now() - startedAt; + $.info(`${monitor.name} latency: ${latency}`); + data.avg_delay.push(latency); + } catch (e) { + $.error(e); + data.avg_delay.push(0); + } + + data.created_at.push( + Date.now() - interval * (monitor.number - index - 1), + ); + } + + result.result.push(data); + } + } catch (e) { + $.error(e); + result.result.push({ + monitor_id: 0, + server_id: 0, + monitor_name: `❌ ${e.message ?? e}`, + server_name: proxy.name, + created_at: [Date.now()], + avg_delay: [0], + }); + } + + return JSON.stringify(result, null, 2); +} +function nezhaTransform(output) { + const result = { + code: 0, + message: 'success', + result: [], + }; + output.map((proxy, index) => { + // 如果节点上有数据 就取节点上的数据 + let CountryCode = proxy._geo?.countryCode || proxy._geo?.country; + // 简单判断下 + if (!/^[a-z]{2}$/i.test(CountryCode)) { + CountryCode = getISO(proxy.name); + } + // 简单判断下 + if (/^[a-z]{2}$/i.test(CountryCode)) { + // 如果节点上有数据 就取节点上的数据 + let now = Math.round(new Date().getTime() / 1000); + let time = proxy._unavailable ? 0 : now; + + const uptime = parseInt(proxy._uptime || 0, 10); + + result.result.push({ + id: index, + name: proxy.name, + tag: `${proxy._tag ?? ''}`, + last_active: time, + // 暂时不用处理 现在 VPings App 端的接口支持域名查询 + // 其他场景使用 自己在 Sub-Store 加一步域名解析 + valid_ip: proxy._IP || proxy.server, + ipv4: proxy._IPv4 || proxy.server, + ipv6: proxy._IPv6 || (isIPv6(proxy.server) ? proxy.server : ''), + host: { + Platform: 'Sub-Store', + PlatformVersion: env.version, + CPU: [], + MemTotal: 1024, + DiskTotal: 1024, + SwapTotal: 1024, + Arch: '', + Virtualization: '', + BootTime: now - uptime, + CountryCode, // 目前需要 + Version: '0.0.1', + }, + status: { + CPU: 0, + MemUsed: 0, + SwapUsed: 0, + DiskUsed: 0, + NetInTransfer: 0, + NetOutTransfer: 0, + NetInSpeed: 0, + NetOutSpeed: 0, + Uptime: uptime, + Load1: 0, + Load5: 0, + Load15: 0, + TcpConnCount: 0, + UdpConnCount: 0, + ProcessCount: 0, + }, + }); + } + }); + return JSON.stringify(result, null, 2); +} diff --git a/backend/src/restful/errors/index.js b/backend/src/restful/errors/index.js new file mode 100644 index 0000000000..a1946b4e2a --- /dev/null +++ b/backend/src/restful/errors/index.js @@ -0,0 +1,35 @@ +class BaseError { + constructor(code, message, details) { + this.code = code; + this.message = message; + this.details = details; + } +} + +export class InternalServerError extends BaseError { + constructor(code, message, details) { + super(code, message, details); + this.type = 'InternalServerError'; + } +} + +export class RequestInvalidError extends BaseError { + constructor(code, message, details) { + super(code, message, details); + this.type = 'RequestInvalidError'; + } +} + +export class ResourceNotFoundError extends BaseError { + constructor(code, message, details) { + super(code, message, details); + this.type = 'ResourceNotFoundError'; + } +} + +export class NetworkError extends BaseError { + constructor(code, message, details) { + super(code, message, details); + this.type = 'NetworkError'; + } +} diff --git a/backend/src/restful/file.js b/backend/src/restful/file.js new file mode 100644 index 0000000000..1744f5eeec --- /dev/null +++ b/backend/src/restful/file.js @@ -0,0 +1,314 @@ +import { deleteByName, findByName, updateByName } from '@/utils/database'; +import { getFlowHeaders, normalizeFlowHeader } from '@/utils/flow'; +import { FILES_KEY, ARTIFACTS_KEY } from '@/constants'; +import { failed, success } from '@/restful/response'; +import $ from '@/core/app'; +import { + RequestInvalidError, + ResourceNotFoundError, + InternalServerError, +} from '@/restful/errors'; +import { produceArtifact } from '@/restful/sync'; +import { formatDateTime } from '@/utils'; + +export default function register($app) { + if (!$.read(FILES_KEY)) $.write([], FILES_KEY); + + $app.get('/share/file/:name', getFile); + + $app.route('/api/file/:name') + .get(getFile) + .patch(updateFile) + .delete(deleteFile); + + $app.route('/api/wholeFile/:name').get(getWholeFile); + + $app.route('/api/files').get(getAllFiles).post(createFile).put(replaceFile); + $app.route('/api/wholeFiles').get(getAllWholeFiles); +} + +// file API +function createFile(req, res) { + const file = req.body; + file.name = `${file.name ?? Date.now()}`; + $.info(`正在创建文件:${file.name}`); + const allFiles = $.read(FILES_KEY); + if (findByName(allFiles, file.name)) { + return failed( + res, + new RequestInvalidError( + 'DUPLICATE_KEY', + req.body.name + ? `已存在 name 为 ${file.name} 的文件` + : `无法同时创建相同的文件 可稍后重试`, + ), + ); + } + allFiles.push(file); + $.write(allFiles, FILES_KEY); + success(res, file, 201); +} + +async function getFile(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + const reqUA = req.headers['user-agent'] || req.headers['User-Agent']; + $.info(`正在下载文件:${name}\n请求 User-Agent: ${reqUA}`); + let { + url, + subInfoUrl, + subInfoUserAgent, + ua, + content, + mergeSources, + ignoreFailedRemoteFile, + proxy, + noCache, + } = req.query; + let $options = { + _req: { + method: req.method, + url: req.url, + path: req.path, + query: req.query, + params: req.params, + headers: req.headers, + body: req.body, + }, + }; + if (req.query.$options) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $options = JSON.parse(decodeURIComponent(req.query.$options)); + } catch (e) { + for (const pair of req.query.$options.split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $options[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + $.info(`传入 $options: ${JSON.stringify($options)}`); + } + if (url) { + url = decodeURIComponent(url); + $.info(`指定远程文件 URL: ${url}`); + } + if (proxy) { + proxy = decodeURIComponent(proxy); + $.info(`指定远程订阅使用代理/策略 proxy: ${proxy}`); + } + if (ua) { + ua = decodeURIComponent(ua); + $.info(`指定远程文件 User-Agent: ${ua}`); + } + if (subInfoUrl) { + subInfoUrl = decodeURIComponent(subInfoUrl); + $.info(`指定获取流量的 subInfoUrl: ${subInfoUrl}`); + } + if (subInfoUserAgent) { + subInfoUserAgent = decodeURIComponent(subInfoUserAgent); + $.info(`指定获取流量的 subInfoUserAgent: ${subInfoUserAgent}`); + } + if (content) { + content = decodeURIComponent(content); + $.info(`指定本地文件: ${content}`); + } + if (mergeSources) { + mergeSources = decodeURIComponent(mergeSources); + $.info(`指定合并来源: ${mergeSources}`); + } + if (ignoreFailedRemoteFile != null && ignoreFailedRemoteFile !== '') { + ignoreFailedRemoteFile = decodeURIComponent(ignoreFailedRemoteFile); + $.info(`指定忽略失败的远程文件: ${ignoreFailedRemoteFile}`); + } + if (noCache) { + $.info(`指定不使用缓存: ${noCache}`); + } + + const allFiles = $.read(FILES_KEY); + const file = findByName(allFiles, name); + if (file) { + try { + const output = await produceArtifact({ + type: 'file', + name, + url, + ua, + content, + mergeSources, + ignoreFailedRemoteFile, + $options, + proxy, + noCache, + }); + + try { + subInfoUrl = subInfoUrl || file.subInfoUrl; + if (subInfoUrl) { + // forward flow headers + const flowInfo = await getFlowHeaders( + subInfoUrl, + subInfoUserAgent || file.subInfoUserAgent, + undefined, + proxy || file.proxy, + ); + if (flowInfo) { + res.set( + 'subscription-userinfo', + normalizeFlowHeader(flowInfo), + ); + } + } + } catch (err) { + $.error( + `文件 ${name} 获取流量信息时发生错误: ${JSON.stringify( + err, + )}`, + ); + } + if (file.download) { + res.set( + 'Content-Disposition', + `attachment; filename*=UTF-8''${encodeURIComponent( + file.displayName || file.name, + )}`, + ); + } + res.set('Content-Type', 'text/plain; charset=utf-8').send( + output ?? '', + ); + } catch (err) { + $.notify( + `🌍 Sub-Store 下载文件失败`, + `❌ 无法下载文件:${name}!`, + `🤔 原因:${err.message ?? err}`, + ); + $.error(err.message ?? err); + failed( + res, + new InternalServerError( + 'INTERNAL_SERVER_ERROR', + `Failed to download file: ${name}`, + `Reason: ${err.message ?? err}`, + ), + ); + } + } else { + $.error(`🌍 Sub-Store 下载文件失败\n❌ 未找到文件:${name}!`); + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `File ${name} does not exist!`, + ), + 404, + ); + } +} +function getWholeFile(req, res) { + let { name } = req.params; + let { raw } = req.query; + name = decodeURIComponent(name); + const allFiles = $.read(FILES_KEY); + const file = findByName(allFiles, name); + if (file) { + if (raw) { + res.set('content-type', 'application/json') + .set( + 'content-disposition', + `attachment; filename="${encodeURIComponent( + `sub-store_file_${name}_${formatDateTime( + new Date(), + )}.json`, + )}"`, + ) + .send(JSON.stringify(file)); + } else { + success(res, file); + } + } else { + failed( + res, + new ResourceNotFoundError( + `FILE_NOT_FOUND`, + `File ${name} does not exist`, + 404, + ), + ); + } +} + +function updateFile(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + let file = req.body; + const allFiles = $.read(FILES_KEY); + const oldFile = findByName(allFiles, name); + if (oldFile) { + const newFile = { + ...oldFile, + ...file, + }; + $.info(`正在更新文件:${name}...`); + + if (name !== newFile.name) { + // update all artifacts referring this collection + const allArtifacts = $.read(ARTIFACTS_KEY) || []; + for (const artifact of allArtifacts) { + if ( + artifact.type === 'file' && + artifact.source === oldFile.name + ) { + artifact.source = newFile.name; + } + } + $.write(allArtifacts, ARTIFACTS_KEY); + } + + updateByName(allFiles, name, newFile); + $.write(allFiles, FILES_KEY); + success(res, newFile); + } else { + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `File ${name} does not exist!`, + ), + 404, + ); + } +} + +function deleteFile(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + $.info(`正在删除文件:${name}`); + let allFiles = $.read(FILES_KEY); + deleteByName(allFiles, name); + $.write(allFiles, FILES_KEY); + success(res); +} + +function getAllFiles(req, res) { + const allFiles = $.read(FILES_KEY); + success( + res, // eslint-disable-next-line no-unused-vars + allFiles.map(({ content, ...rest }) => rest), + ); +} + +function getAllWholeFiles(req, res) { + const allFiles = $.read(FILES_KEY); + success(res, allFiles); +} + +function replaceFile(req, res) { + const allFiles = req.body; + $.write(allFiles, FILES_KEY); + success(res); +} diff --git a/backend/src/restful/index.js b/backend/src/restful/index.js new file mode 100644 index 0000000000..7f5222daec --- /dev/null +++ b/backend/src/restful/index.js @@ -0,0 +1,431 @@ +import express from '@/vendor/express'; +import $ from '@/core/app'; +import migrate from '@/utils/migration'; +import download, { downloadFile } from '@/utils/download'; +import { syncArtifacts, produceArtifact } from '@/restful/sync'; +import { gistBackupAction } from '@/restful/miscs'; +import { TOKENS_KEY } from '@/constants'; + +import registerSubscriptionRoutes from './subscriptions'; +import registerCollectionRoutes from './collections'; +import registerArtifactRoutes from './artifacts'; +import registerFileRoutes from './file'; +import registerTokenRoutes from './token'; +import registerModuleRoutes from './module'; +import registerSyncRoutes from './sync'; +import registerDownloadRoutes from './download'; +import registerSettingRoutes from './settings'; +import registerPreviewRoutes from './preview'; +import registerSortingRoutes from './sort'; +import registerMiscRoutes from './miscs'; +import registerNodeInfoRoutes from './node-info'; +import registerParserRoutes from './parser'; + +export default function serve() { + let port; + let host; + if ($.env.isNode) { + port = eval('process.env.SUB_STORE_BACKEND_API_PORT') || 3000; + host = eval('process.env.SUB_STORE_BACKEND_API_HOST') || '::'; + } + const $app = express({ substore: $, port, host }); + if ($.env.isNode) { + const be_merge = eval('process.env.SUB_STORE_BACKEND_MERGE'); + const be_prefix = eval('process.env.SUB_STORE_BACKEND_PREFIX'); + const fe_be_path = eval('process.env.SUB_STORE_FRONTEND_BACKEND_PATH'); + const fe_path = eval('process.env.SUB_STORE_FRONTEND_PATH'); + if (be_prefix || be_merge) { + if (!fe_be_path.startsWith('/')) { + throw new Error( + 'SUB_STORE_FRONTEND_BACKEND_PATH should start with /', + ); + } + if (be_merge) { + $.info(`[BACKEND] MERGE mode is [ON].`); + $.info(`[BACKEND && FRONTEND] ${host}:${port}`); + } + $.info(`[BACKEND PREFIX] ${host}:${port}${fe_be_path}`); + $app.use((req, res, next) => { + if (req.path.startsWith(fe_be_path)) { + req.url = req.url.replace(fe_be_path, '') || '/'; + if (be_merge && req.url.startsWith('/api/')) { + req.query['share'] = 'true'; + } + next(); + return; + } + const pathname = + decodeURIComponent(req._parsedUrl.pathname) || '/'; + if ( + be_merge && + req.path.startsWith('/share/') && + req.query.token + ) { + if (req.method.toLowerCase() !== 'get') { + res.status(405).send('Method not allowed'); + return; + } + const tokens = $.read(TOKENS_KEY) || []; + const token = tokens.find( + (t) => + t.token === req.query.token && + `/share/${t.type}/${t.name}` === pathname && + (t.exp == null || t.exp > Date.now()), + ); + if (token) { + next(); + return; + } + } + if (be_merge && fe_path && req.path.indexOf('/', 1) == -1) { + if (req.path.indexOf('.') == -1) { + req.url = '/index.html'; + } + const express_ = eval(`require("express")`); + const mime_ = eval(`require("mime-types")`); + const path_ = eval(`require("path")`); + const staticFileMiddleware = express_.static(fe_path, { + setHeaders: (res, path) => { + const type = mime_.contentType(path_.extname(path)); + if (type) { + res.set('Content-Type', type); + } + }, + }); + staticFileMiddleware(req, res, next); + return; + } + res.status(403).end('Forbbiden'); + return; + }); + } + } + // register routes + registerCollectionRoutes($app); + registerSubscriptionRoutes($app); + registerDownloadRoutes($app); + registerPreviewRoutes($app); + registerSortingRoutes($app); + registerSettingRoutes($app); + registerArtifactRoutes($app); + registerFileRoutes($app); + registerTokenRoutes($app); + registerModuleRoutes($app); + registerSyncRoutes($app); + registerNodeInfoRoutes($app); + registerMiscRoutes($app); + registerParserRoutes($app); + + $app.start(); + + if ($.env.isNode) { + // Deprecated: SUB_STORE_BACKEND_CRON + const backend_sync_cron = + eval('process.env.SUB_STORE_BACKEND_SYNC_CRON') || + eval('process.env.SUB_STORE_BACKEND_CRON'); + if (backend_sync_cron) { + $.info(`[SYNC CRON] ${backend_sync_cron} enabled`); + const { CronJob } = eval(`require("cron")`); + new CronJob( + backend_sync_cron, + async function () { + try { + $.info(`[SYNC CRON] ${backend_sync_cron} started`); + await syncArtifacts(); + $.info(`[SYNC CRON] ${backend_sync_cron} finished`); + } catch (e) { + $.error( + `[SYNC CRON] ${backend_sync_cron} error: ${ + e.message ?? e + }`, + ); + } + }, // onTick + null, // onComplete + true, // start + // 'Asia/Shanghai' // timeZone + ); + } + // 格式: 0 */2 * * *,sub,a;0 */3 * * *,col,b + // 每 2 小时处理一次单条订阅 a, 每 3 小时处理一次组合订阅 b + const produce_cron = eval('process.env.SUB_STORE_PRODUCE_CRON'); + if (produce_cron) { + $.info(`[PRODUCE CRON] ${produce_cron} enabled`); + const { CronJob } = eval(`require("cron")`); + produce_cron.split(/\s*;\s*/).map((item) => { + const [cron, type, name] = item.split(/\s*,\s*/); + new CronJob( + cron.trim(), + async function () { + try { + $.info( + `[PRODUCE CRON] ${type} ${name} ${cron} started`, + ); + await produceArtifact({ type, name }); + $.info( + `[PRODUCE CRON] ${type} ${name} ${cron} finished`, + ); + } catch (e) { + $.error( + `[PRODUCE CRON] ${type} ${name} ${cron} error: ${ + e.message ?? e + }`, + ); + } + }, // onTick + null, // onComplete + true, // start + // 'Asia/Shanghai' // timeZone + ); + }); + } + const backend_download_cron = eval( + 'process.env.SUB_STORE_BACKEND_DOWNLOAD_CRON', + ); + if (backend_download_cron) { + $.info(`[DOWNLOAD CRON] ${backend_download_cron} enabled`); + const { CronJob } = eval(`require("cron")`); + new CronJob( + backend_download_cron, + async function () { + try { + $.info( + `[DOWNLOAD CRON] ${backend_download_cron} started`, + ); + await gistBackupAction('download'); + $.info( + `[DOWNLOAD CRON] ${backend_download_cron} finished`, + ); + } catch (e) { + $.error( + `[DOWNLOAD CRON] ${backend_download_cron} error: ${ + e.message ?? e + }`, + ); + } + }, // onTick + null, // onComplete + true, // start + // 'Asia/Shanghai' // timeZone + ); + } + const backend_upload_cron = eval( + 'process.env.SUB_STORE_BACKEND_UPLOAD_CRON', + ); + if (backend_upload_cron) { + $.info(`[UPLOAD CRON] ${backend_upload_cron} enabled`); + const { CronJob } = eval(`require("cron")`); + new CronJob( + backend_upload_cron, + async function () { + try { + $.info(`[UPLOAD CRON] ${backend_upload_cron} started`); + await gistBackupAction('upload'); + $.info(`[UPLOAD CRON] ${backend_upload_cron} finished`); + } catch (e) { + $.error( + `[UPLOAD CRON] ${backend_upload_cron} error: ${ + e.message ?? e + }`, + ); + } + }, // onTick + null, // onComplete + true, // start + // 'Asia/Shanghai' // timeZone + ); + } + const mmdb_cron = eval('process.env.SUB_STORE_MMDB_CRON'); + const countryFile = eval('process.env.SUB_STORE_MMDB_COUNTRY_PATH'); + const countryUrl = eval('process.env.SUB_STORE_MMDB_COUNTRY_URL'); + const asnFile = eval('process.env.SUB_STORE_MMDB_ASN_PATH'); + const asnUrl = eval('process.env.SUB_STORE_MMDB_ASN_URL'); + if (mmdb_cron && ((countryFile && countryUrl) || (asnFile && asnUrl))) { + $.info(`[MMDB CRON] ${mmdb_cron} enabled`); + const { CronJob } = eval(`require("cron")`); + new CronJob( + mmdb_cron, + async function () { + try { + $.info(`[MMDB CRON] ${mmdb_cron} started`); + if (countryFile && countryUrl) { + try { + $.info( + `[MMDB CRON] downloading ${countryUrl} to ${countryFile}`, + ); + await downloadFile(countryUrl, countryFile); + } catch (e) { + $.error( + `[MMDB CRON] ${countryUrl} download failed: ${ + e.message ?? e + }`, + ); + } + } + if (asnFile && asnUrl) { + try { + $.info( + `[MMDB CRON] downloading ${asnUrl} to ${asnFile}`, + ); + await downloadFile(asnUrl, asnFile); + } catch (e) { + $.error( + `[MMDB CRON] ${asnUrl} download failed: ${ + e.message ?? e + }`, + ); + } + } + + $.info(`[MMDB CRON] ${mmdb_cron} finished`); + } catch (e) { + $.error( + `[MMDB CRON] ${mmdb_cron} error: ${e.message ?? e}`, + ); + } + }, // onTick + null, // onComplete + true, // start + // 'Asia/Shanghai' // timeZone + ); + } + const path = eval(`require("path")`); + const fs = eval(`require("fs")`); + const data_url = eval('process.env.SUB_STORE_DATA_URL'); + const fe_be_path = eval('process.env.SUB_STORE_FRONTEND_BACKEND_PATH'); + const fe_port = eval('process.env.SUB_STORE_FRONTEND_PORT') || 3001; + const fe_host = + eval('process.env.SUB_STORE_FRONTEND_HOST') || host || '::'; + const fe_path = eval('process.env.SUB_STORE_FRONTEND_PATH'); + const fe_abs_path = path.resolve( + fe_path || path.join(__dirname, 'frontend'), + ); + const be_merge = eval('process.env.SUB_STORE_BACKEND_MERGE'); + if (fe_path && !be_merge) { + try { + fs.accessSync(path.join(fe_abs_path, 'index.html')); + } catch (e) { + $.error( + `[FRONTEND] index.html file not found in ${fe_abs_path}`, + ); + } + + const express_ = eval(`require("express")`); + const history = eval(`require("connect-history-api-fallback")`); + const { createProxyMiddleware } = eval( + `require("http-proxy-middleware")`, + ); + + const app = express_(); + + const staticFileMiddleware = express_.static(fe_path); + + let be_api = '/api/'; + let be_download = '/download/'; + let be_share = '/share/'; + let be_download_rewrite = ''; + let be_api_rewrite = ''; + let be_share_rewrite = `${be_share}:type/:name`; + let prefix = eval('process.env.SUB_STORE_BACKEND_PREFIX') + ? fe_be_path + : ''; + if (fe_be_path) { + if (!fe_be_path.startsWith('/')) { + throw new Error( + 'SUB_STORE_FRONTEND_BACKEND_PATH should start with /', + ); + } + be_api_rewrite = `${ + fe_be_path === '/' ? '' : fe_be_path + }${be_api}`; + be_download_rewrite = `${ + fe_be_path === '/' ? '' : fe_be_path + }${be_download}`; + + app.use( + be_share_rewrite, + createProxyMiddleware({ + target: `http://127.0.0.1:${port}${prefix}`, + changeOrigin: true, + pathRewrite: async (path, req) => { + if (req.method.toLowerCase() !== 'get') + throw new Error('Method not allowed'); + const tokens = $.read(TOKENS_KEY) || []; + const token = tokens.find( + (t) => + t.token === req.query.token && + t.type === req.params.type && + t.name === req.params.name && + (t.exp == null || t.exp > Date.now()), + ); + if (!token) throw new Error('Forbbiden'); + return req.originalUrl; + }, + }), + ); + app.use( + be_api_rewrite, + createProxyMiddleware({ + target: `http://127.0.0.1:${port}${prefix}${be_api}`, + pathRewrite: async (path) => { + return path.includes('?') + ? `${path}&share=true` + : `${path}?share=true`; + }, + }), + ); + app.use( + be_download_rewrite, + createProxyMiddleware({ + target: `http://127.0.0.1:${port}${prefix}${be_download}`, + changeOrigin: true, + }), + ); + } + + app.use(staticFileMiddleware); + app.use( + history({ + disableDotRule: true, + verbose: false, + }), + ); + app.use(staticFileMiddleware); + + const listener = app.listen(fe_port, fe_host, () => { + const { address: fe_address, port: fe_port } = + listener.address(); + $.info(`[FRONTEND] ${fe_address}:${fe_port}`); + if (fe_be_path) { + $.info( + `[FRONTEND -> BACKEND] ${fe_address}:${fe_port}${be_api_rewrite} -> ${host}:${port}${prefix}${be_api}`, + ); + $.info( + `[FRONTEND -> BACKEND] ${fe_address}:${fe_port}${be_download_rewrite} -> ${host}:${port}${prefix}${be_download}`, + ); + $.info( + `[SHARE BACKEND] ${fe_address}:${fe_port}${be_share_rewrite}`, + ); + } + }); + } + if (data_url) { + $.info(`[BACKEND] downloading data from ${data_url}`); + download(data_url) + .then((content) => { + $.write(content, '#sub-store'); + + $.cache = JSON.parse(content); + $.persistCache(); + + migrate(); + $.info(`[BACKEND] restored data from ${data_url}`); + }) + .catch((e) => { + $.error(`[BACKEND] restore data failed`); + console.error(e); + throw e; + }); + } + } +} diff --git a/backend/src/restful/miscs.js b/backend/src/restful/miscs.js new file mode 100644 index 0000000000..9a84239c0e --- /dev/null +++ b/backend/src/restful/miscs.js @@ -0,0 +1,198 @@ +import $ from '@/core/app'; +import { ENV } from '@/vendor/open-api'; +import { failed, success } from '@/restful/response'; +import { updateArtifactStore, updateAvatar } from '@/restful/settings'; +import resourceCache from '@/utils/resource-cache'; +import scriptResourceCache from '@/utils/script-resource-cache'; +import headersResourceCache from '@/utils/headers-resource-cache'; +import { + GIST_BACKUP_FILE_NAME, + GIST_BACKUP_KEY, + SETTINGS_KEY, +} from '@/constants'; +import { InternalServerError, RequestInvalidError } from '@/restful/errors'; +import Gist from '@/utils/gist'; +import migrate from '@/utils/migration'; +import env from '@/utils/env'; +import { formatDateTime } from '@/utils'; + +export default function register($app) { + // utils + $app.get('/api/utils/env', getEnv); // get runtime environment + $app.get('/api/utils/backup', gistBackup); // gist backup actions + $app.get('/api/utils/refresh', refresh); + + // Storage management + $app.route('/api/storage') + .get((req, res) => { + res.set('content-type', 'application/json') + .set( + 'content-disposition', + `attachment; filename="${encodeURIComponent( + `sub-store_data_${formatDateTime(new Date())}.json`, + )}"`, + ) + .send( + $.env.isNode + ? JSON.stringify($.cache) + : $.read('#sub-store'), + ); + }) + .post((req, res) => { + const { content } = req.body; + $.write(content, '#sub-store'); + if ($.env.isNode) { + $.cache = JSON.parse(content); + $.persistCache(); + } + migrate(); + success(res); + }); + + // Redirect sub.store to vercel webpage + $app.get('/', async (req, res) => { + // 302 redirect + res.set('location', 'https://sub-store.vercel.app/').status(302).end(); + }); + + // handle preflight request for QX + if (ENV().isQX) { + $app.options('/', async (req, res) => { + res.status(200).end(); + }); + } + + $app.all('/', (_, res) => { + res.send('Hello from sub-store, made with ❤️ by Peng-YM'); + }); +} + +function getEnv(req, res) { + if (req.query.share) { + env.feature.share = true; + } + success(res, env); +} + +async function refresh(_, res) { + // 1. get GitHub avatar and artifact store + await updateAvatar(); + await updateArtifactStore(); + + // 2. clear resource cache + resourceCache.revokeAll(); + scriptResourceCache.revokeAll(); + headersResourceCache.revokeAll(); + success(res); +} + +async function gistBackupAction(action) { + // read token + const { gistToken, syncPlatform } = $.read(SETTINGS_KEY); + if (!gistToken) throw new Error('GitHub Token is required for backup!'); + + const gist = new Gist({ + token: gistToken, + key: GIST_BACKUP_KEY, + syncPlatform, + }); + let content; + const settings = $.read(SETTINGS_KEY); + const updated = settings.syncTime; + switch (action) { + case 'upload': + try { + content = $.read('#sub-store'); + if ($.env.isNode) content = JSON.stringify($.cache, null, ` `); + $.info(`下载备份, 与本地内容对比...`); + const onlineContent = await gist.download( + GIST_BACKUP_FILE_NAME, + ); + if (onlineContent === content) { + $.info(`内容一致, 无需上传备份`); + return; + } + } catch (error) { + $.error(`${error.message ?? error}`); + } + + // update syncTime + settings.syncTime = new Date().getTime(); + $.write(settings, SETTINGS_KEY); + content = $.read('#sub-store'); + if ($.env.isNode) content = JSON.stringify($.cache, null, ` `); + $.info(`上传备份中...`); + try { + await gist.upload({ + [GIST_BACKUP_FILE_NAME]: { content }, + }); + $.info(`上传备份完成`); + } catch (err) { + // restore syncTime if upload failed + settings.syncTime = updated; + $.write(settings, SETTINGS_KEY); + throw err; + } + break; + case 'download': + $.info(`还原备份中...`); + content = await gist.download(GIST_BACKUP_FILE_NAME); + try { + if (Object.keys(JSON.parse(content).settings).length === 0) { + throw new Error('备份文件应该至少包含 settings 字段'); + } + } catch (err) { + $.error( + `Gist 备份文件校验失败, 无法还原\nReason: ${ + err.message ?? err + }`, + ); + throw new Error('Gist 备份文件校验失败, 无法还原'); + } + // restore settings + $.write(content, '#sub-store'); + if ($.env.isNode) { + content = JSON.parse(content); + $.cache = content; + $.persistCache(); + } + $.info(`perform migration after restoring from gist...`); + migrate(); + $.info(`migration completed`); + $.info(`还原备份完成`); + break; + } +} +async function gistBackup(req, res) { + const { action } = req.query; + // read token + const { gistToken } = $.read(SETTINGS_KEY); + if (!gistToken) { + failed( + res, + new RequestInvalidError( + 'GIST_TOKEN_NOT_FOUND', + `GitHub Token is required for backup!`, + ), + ); + } else { + try { + await gistBackupAction(action); + success(res); + } catch (err) { + $.error( + `Failed to ${action} gist data.\nReason: ${err.message ?? err}`, + ); + failed( + res, + new InternalServerError( + 'BACKUP_FAILED', + `Failed to ${action} gist data!`, + `Reason: ${err.message ?? err}`, + ), + ); + } + } +} + +export { gistBackupAction }; diff --git a/backend/src/restful/module.js b/backend/src/restful/module.js new file mode 100644 index 0000000000..6ef8885548 --- /dev/null +++ b/backend/src/restful/module.js @@ -0,0 +1,116 @@ +import { deleteByName, findByName, updateByName } from '@/utils/database'; +import { MODULES_KEY } from '@/constants'; +import { failed, success } from '@/restful/response'; +import $ from '@/core/app'; +import { RequestInvalidError, ResourceNotFoundError } from '@/restful/errors'; +import { hex_md5 } from '@/vendor/md5'; + +export default function register($app) { + if (!$.read(MODULES_KEY)) $.write([], MODULES_KEY); + + $app.route('/api/module/:name') + .get(getModule) + .patch(updateModule) + .delete(deleteModule); + + $app.route('/api/modules') + .get(getAllModules) + .post(createModule) + .put(replaceModule); +} + +// module API +function createModule(req, res) { + const module = req.body; + module.name = `${module.name ?? hex_md5(JSON.stringify(module))}`; + $.info(`正在创建模块:${module.name}`); + const allModules = $.read(MODULES_KEY); + if (findByName(allModules, module.name)) { + return failed( + res, + new RequestInvalidError( + 'DUPLICATE_KEY', + req.body.name + ? `已存在 name 为 ${module.name} 的模块` + : `已存在相同的模块 请勿重复添加`, + ), + ); + } + allModules.push(module); + $.write(allModules, MODULES_KEY); + success(res, module, 201); +} + +function getModule(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + const allModules = $.read(MODULES_KEY); + const module = findByName(allModules, name); + if (module) { + res.set('Content-Type', 'text/plain; charset=utf-8').send( + module.content, + ); + } else { + failed( + res, + new ResourceNotFoundError( + `MODULE_NOT_FOUND`, + `Module ${name} does not exist`, + 404, + ), + ); + } +} + +function updateModule(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + let module = req.body; + const allModules = $.read(MODULES_KEY); + const oldModule = findByName(allModules, name); + if (oldModule) { + const newModule = { + ...oldModule, + ...module, + }; + $.info(`正在更新模块:${name}...`); + + updateByName(allModules, name, newModule); + $.write(allModules, MODULES_KEY); + success(res, newModule); + } else { + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `Module ${name} does not exist!`, + ), + 404, + ); + } +} + +function deleteModule(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + $.info(`正在删除模块:${name}`); + let allModules = $.read(MODULES_KEY); + deleteByName(allModules, name); + $.write(allModules, MODULES_KEY); + success(res); +} + +function getAllModules(req, res) { + const allModules = $.read(MODULES_KEY); + success( + res, + // eslint-disable-next-line no-unused-vars + allModules.map(({ content, ...rest }) => rest), + ); +} + +function replaceModule(req, res) { + const allModules = req.body; + $.write(allModules, MODULES_KEY); + success(res); +} diff --git a/backend/src/restful/node-info.js b/backend/src/restful/node-info.js new file mode 100644 index 0000000000..17ddc77446 --- /dev/null +++ b/backend/src/restful/node-info.js @@ -0,0 +1,59 @@ +import producer from '@/core/proxy-utils/producers'; +import { HTTP } from '@/vendor/open-api'; +import { failed, success } from '@/restful/response'; +import { NetworkError } from '@/restful/errors'; + +export default function register($app) { + $app.post('/api/utils/node-info', getNodeInfo); +} + +async function getNodeInfo(req, res) { + const proxy = req.body; + const lang = req.query.lang || 'zh-CN'; + let shareUrl; + try { + shareUrl = producer.URI.produce(proxy); + } catch (err) { + // do nothing + } + + try { + const $http = HTTP(); + const info = await $http + .get({ + url: `http://ip-api.com/json/${encodeURIComponent( + `${proxy.server}` + .trim() + .replace(/^\[/, '') + .replace(/\]$/, ''), + )}?lang=${lang}`, + headers: { + 'User-Agent': + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 12_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15', + }, + }) + .then((resp) => { + const data = JSON.parse(resp.body); + if (data.status !== 'success') { + throw new Error(data.message); + } + + // remove unnecessary fields + delete data.status; + return data; + }); + success(res, { + shareUrl, + info, + }); + } catch (err) { + failed( + res, + new NetworkError( + 'FAILED_TO_GET_NODE_INFO', + `Failed to get node info`, + `Reason: ${err}`, + ), + ); + } +} diff --git a/backend/src/restful/parser.js b/backend/src/restful/parser.js new file mode 100644 index 0000000000..d5b1888b18 --- /dev/null +++ b/backend/src/restful/parser.js @@ -0,0 +1,54 @@ +import { success, failed } from '@/restful/response'; +import { ProxyUtils } from '@/core/proxy-utils'; +import { RuleUtils } from '@/core/rule-utils'; + +export default function register($app) { + $app.route('/api/proxy/parse').post(proxy_parser); + $app.route('/api/rule/parse').post(rule_parser); +} + +/*** + * 感谢 izhangxm 的 PR! + * 目前没有节点操作, 没有支持完整参数, 以后再完善一下 + */ + +/*** + * 代理服务器协议转换接口。 + * 请求方法为POST,数据为json。需要提供data和client字段。 + * data: string, 协议数据,每行一个或者是clash + * client: string, 目标平台名称,见backend/src/core/proxy-utils/producers/index.js + * + */ +function proxy_parser(req, res) { + const { data, client, content, platform } = req.body; + var result = {}; + try { + var proxies = ProxyUtils.parse(data ?? content); + var par_res = ProxyUtils.produce(proxies, client ?? platform); + result['par_res'] = par_res; + } catch (err) { + failed(res, err); + return; + } + success(res, result); +} +/** + * 规则转换接口。 + * 请求方法为POST,数据为json。需要提供data和client字段。 + * data: string, 多行规则字符串 + * client: string, 目标平台名称,具体见backend/src/core/rule-utils/producers.js + */ +function rule_parser(req, res) { + const { data, client, content, platform } = req.body; + var result = {}; + try { + const rules = RuleUtils.parse(data ?? content); + var par_res = RuleUtils.produce(rules, client ?? platform); + result['par_res'] = par_res; + } catch (err) { + failed(res, err); + return; + } + + success(res, result); +} diff --git a/backend/src/restful/preview.js b/backend/src/restful/preview.js new file mode 100644 index 0000000000..03ef0479e5 --- /dev/null +++ b/backend/src/restful/preview.js @@ -0,0 +1,368 @@ +import { InternalServerError } from './errors'; +import { ProxyUtils } from '@/core/proxy-utils'; +import { findByName } from '@/utils/database'; +import { success, failed } from './response'; +import download from '@/utils/download'; +import { SUBS_KEY } from '@/constants'; +import $ from '@/core/app'; + +export default function register($app) { + $app.post('/api/preview/sub', compareSub); + $app.post('/api/preview/collection', compareCollection); + $app.post('/api/preview/file', previewFile); +} + +async function previewFile(req, res) { + try { + const file = req.body; + let content = ''; + if (file.type !== 'mihomoProfile') { + if ( + file.source === 'local' && + !['localFirst', 'remoteFirst'].includes(file.mergeSources) + ) { + content = file.content; + } else { + const errors = {}; + content = await Promise.all( + file.url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + file.ua, + undefined, + file.proxy, + ); + } catch (err) { + errors[url] = err; + $.error( + `文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + + if (Object.keys(errors).length > 0) { + if (!file.ignoreFailedRemoteFile) { + throw new Error( + `文件 ${file.name} 的远程文件 ${Object.keys( + errors, + ).join(', ')} 发生错误, 请查看日志`, + ); + } else if (file.ignoreFailedRemoteFile === 'enabled') { + $.notify( + `🌍 Sub-Store 预览文件失败`, + `❌ ${file.name}`, + `远程文件 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + if (file.mergeSources === 'localFirst') { + content.unshift(file.content); + } else if (file.mergeSources === 'remoteFirst') { + content.push(file.content); + } + } + } + // parse proxies + const files = (Array.isArray(content) ? content : [content]).flat(); + let filesContent = files + .filter((i) => i != null && i !== '') + .join('\n'); + + // apply processors + const processed = + Array.isArray(file.process) && file.process.length > 0 + ? await ProxyUtils.process( + { $files: files, $content: filesContent, $file: file }, + file.process, + ) + : { $content: filesContent, $files: files }; + + // produce + success(res, { + original: filesContent, + processed: processed?.$content ?? '', + }); + } catch (err) { + $.error(err.message ?? err); + failed( + res, + new InternalServerError( + `INTERNAL_SERVER_ERROR`, + `Failed to preview file`, + `Reason: ${err.message ?? err}`, + ), + ); + } +} + +async function compareSub(req, res) { + try { + const sub = req.body; + const target = req.query.target || 'JSON'; + let content; + if ( + sub.source === 'local' && + !['localFirst', 'remoteFirst'].includes(sub.mergeSources) + ) { + content = sub.content; + } else { + const errors = {}; + content = await Promise.all( + sub.url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + sub.ua, + undefined, + sub.proxy, + undefined, + undefined, + undefined, + true, + ); + } catch (err) { + errors[url] = err; + $.error( + `订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + + if (Object.keys(errors).length > 0) { + if (!sub.ignoreFailedRemoteSub) { + throw new Error( + `订阅 ${sub.name} 的远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } else if (sub.ignoreFailedRemoteSub === 'enabled') { + $.notify( + `🌍 Sub-Store 预览订阅失败`, + `❌ ${sub.name}`, + `远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + if (sub.mergeSources === 'localFirst') { + content.unshift(sub.content); + } else if (sub.mergeSources === 'remoteFirst') { + content.push(sub.content); + } + } + // parse proxies + const original = (Array.isArray(content) ? content : [content]) + .map((i) => ProxyUtils.parse(i)) + .flat(); + + // add id + original.forEach((proxy, i) => { + proxy.id = i; + proxy._subName = sub.name; + proxy._subDisplayName = sub.displayName; + }); + + // apply processors + const processed = await ProxyUtils.process( + original, + sub.process || [], + target, + { [sub.name]: sub }, + ); + + // produce + success(res, { original, processed }); + } catch (err) { + $.error(err.message ?? err); + failed( + res, + new InternalServerError( + `INTERNAL_SERVER_ERROR`, + `Failed to preview subscription`, + `Reason: ${err.message ?? err}`, + ), + ); + } +} + +async function compareCollection(req, res) { + try { + const allSubs = $.read(SUBS_KEY); + const collection = req.body; + const subnames = [...collection.subscriptions]; + let subscriptionTags = collection.subscriptionTags; + if (Array.isArray(subscriptionTags) && subscriptionTags.length > 0) { + allSubs.forEach((sub) => { + if ( + Array.isArray(sub.tag) && + sub.tag.length > 0 && + !subnames.includes(sub.name) && + sub.tag.some((tag) => subscriptionTags.includes(tag)) + ) { + subnames.push(sub.name); + } + }); + } + const results = {}; + const errors = {}; + await Promise.all( + subnames.map(async (name) => { + const sub = findByName(allSubs, name); + try { + let raw; + if ( + sub.source === 'local' && + !['localFirst', 'remoteFirst'].includes( + sub.mergeSources, + ) + ) { + raw = sub.content; + } else { + const errors = {}; + raw = await Promise.all( + sub.url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + sub.ua, + undefined, + sub.proxy, + undefined, + undefined, + undefined, + true, + ); + } catch (err) { + errors[url] = err; + $.error( + `订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + + if (Object.keys(errors).length > 0) { + if (!sub.ignoreFailedRemoteSub) { + throw new Error( + `订阅 ${sub.name} 的远程订阅 ${Object.keys( + errors, + ).join(', ')} 发生错误, 请查看日志`, + ); + } else if ( + sub.ignoreFailedRemoteSub === 'enabled' + ) { + $.notify( + `🌍 Sub-Store 预览订阅失败`, + `❌ ${sub.name}`, + `远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + if (sub.mergeSources === 'localFirst') { + raw.unshift(sub.content); + } else if (sub.mergeSources === 'remoteFirst') { + raw.push(sub.content); + } + } + // parse proxies + let currentProxies = (Array.isArray(raw) ? raw : [raw]) + .map((i) => ProxyUtils.parse(i)) + .flat(); + + currentProxies.forEach((proxy) => { + proxy._subName = sub.name; + proxy._subDisplayName = sub.displayName; + proxy._collectionName = collection.name; + proxy._collectionDisplayName = collection.displayName; + }); + + // apply processors + currentProxies = await ProxyUtils.process( + currentProxies, + sub.process || [], + 'JSON', + { [sub.name]: sub, _collection: collection }, + ); + results[name] = currentProxies; + } catch (err) { + errors[name] = err; + + $.error( + `❌ 处理组合订阅 ${collection.name} 中的子订阅: ${sub.name} 时出现错误:${err}!`, + ); + } + }), + ); + + if (Object.keys(errors).length > 0) { + if (!collection.ignoreFailedRemoteSub) { + throw new Error( + `组合订阅 ${collection.name} 的子订阅 ${Object.keys( + errors, + ).join(', ')} 发生错误, 请查看日志`, + ); + } else if (collection.ignoreFailedRemoteSub === 'enabled') { + $.notify( + `🌍 Sub-Store 预览组合订阅失败`, + `❌ ${collection.name}`, + `子订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + // merge proxies with the original order + const original = Array.prototype.concat.apply( + [], + subnames.map((name) => results[name] || []), + ); + + original.forEach((proxy, i) => { + proxy.id = i; + proxy._collectionName = collection.name; + proxy._collectionDisplayName = collection.displayName; + }); + + const processed = await ProxyUtils.process( + original, + collection.process || [], + 'JSON', + { _collection: collection }, + ); + + success(res, { original, processed }); + } catch (err) { + $.error(err.message ?? err); + failed( + res, + new InternalServerError( + `INTERNAL_SERVER_ERROR`, + `Failed to preview collection`, + `Reason: ${err.message ?? err}`, + ), + ); + } +} diff --git a/backend/src/restful/response.js b/backend/src/restful/response.js new file mode 100644 index 0000000000..4ded891355 --- /dev/null +++ b/backend/src/restful/response.js @@ -0,0 +1,18 @@ +export function success(resp, data, statusCode) { + resp.status(statusCode || 200).json({ + status: 'success', + data, + }); +} + +export function failed(resp, error, statusCode) { + resp.status(statusCode || 500).json({ + status: 'failed', + error: { + code: error.code, + type: error.type, + message: error.message, + details: error.details, + }, + }); +} diff --git a/backend/src/restful/settings.js b/backend/src/restful/settings.js new file mode 100644 index 0000000000..fa623da8e9 --- /dev/null +++ b/backend/src/restful/settings.js @@ -0,0 +1,150 @@ +import { SETTINGS_KEY, ARTIFACT_REPOSITORY_KEY } from '@/constants'; +import { success, failed } from './response'; +import { InternalServerError } from '@/restful/errors'; +import $ from '@/core/app'; +import Gist from '@/utils/gist'; + +export default function register($app) { + const settings = $.read(SETTINGS_KEY); + if (!settings) $.write({}, SETTINGS_KEY); + $app.route('/api/settings').get(getSettings).patch(updateSettings); +} + +async function getSettings(req, res) { + try { + let settings = $.read(SETTINGS_KEY); + if (!settings) { + settings = {}; + $.write(settings, SETTINGS_KEY); + } + + if (!settings.avatarUrl) await updateAvatar(); + if (!settings.artifactStore) await updateArtifactStore(); + + success(res, settings); + } catch (e) { + $.error(`Failed to get settings: ${e.message ?? e}`); + failed( + res, + new InternalServerError( + `FAILED_TO_GET_SETTINGS`, + `Failed to get settings`, + `Reason: ${e.message ?? e}`, + ), + ); + } +} + +async function updateSettings(req, res) { + try { + const settings = $.read(SETTINGS_KEY); + const newSettings = { + ...settings, + ...req.body, + }; + $.write(newSettings, SETTINGS_KEY); + await updateAvatar(); + await updateArtifactStore(); + success(res, newSettings); + } catch (e) { + $.error(`Failed to update settings: ${e.message ?? e}`); + failed( + res, + new InternalServerError( + `FAILED_TO_UPDATE_SETTINGS`, + `Failed to update settings`, + `Reason: ${e.message ?? e}`, + ), + ); + } +} + +export async function updateAvatar() { + const settings = $.read(SETTINGS_KEY); + const { githubUser: username, syncPlatform } = settings; + if (username) { + if (syncPlatform === 'gitlab') { + try { + const data = await $.http + .get({ + url: `https://gitlab.com/api/v4/users?username=${encodeURIComponent( + username, + )}`, + headers: { + 'User-Agent': + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.141 Safari/537.36', + }, + }) + .then((resp) => JSON.parse(resp.body)); + settings.avatarUrl = data[0]['avatar_url'].replace( + /(\?|&)s=\d+(&|$)/, + '$1s=160$2', + ); + $.write(settings, SETTINGS_KEY); + } catch (err) { + $.error( + `Failed to fetch GitLab avatar for User: ${username}. Reason: ${ + err.message ?? err + }`, + ); + } + } else { + try { + const data = await $.http + .get({ + url: `https://api.github.com/users/${encodeURIComponent( + username, + )}`, + headers: { + 'User-Agent': + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.141 Safari/537.36', + }, + }) + .then((resp) => JSON.parse(resp.body)); + settings.avatarUrl = data['avatar_url']; + $.write(settings, SETTINGS_KEY); + } catch (err) { + $.error( + `Failed to fetch GitHub avatar for User: ${username}. Reason: ${ + err.message ?? err + }`, + ); + } + } + } +} + +export async function updateArtifactStore() { + $.log('Updating artifact store'); + const settings = $.read(SETTINGS_KEY); + const { gistToken, syncPlatform } = settings; + if (gistToken) { + const manager = new Gist({ + token: gistToken, + key: ARTIFACT_REPOSITORY_KEY, + syncPlatform, + }); + + try { + const gist = await manager.locate(); + const url = gist?.html_url ?? gist?.web_url; + if (url) { + $.log(`找到 Sub-Store Gist: ${url}`); + // 只需要保证 token 是对的, 现在 username 错误只会导致头像错误 + settings.artifactStore = url; + settings.artifactStoreStatus = 'VALID'; + } else { + $.error(`找不到 Sub-Store Gist (${ARTIFACT_REPOSITORY_KEY})`); + settings.artifactStoreStatus = 'NOT FOUND'; + } + } catch (err) { + $.error( + `查找 Sub-Store Gist (${ARTIFACT_REPOSITORY_KEY}) 时发生错误: ${ + err.message ?? err + }`, + ); + settings.artifactStoreStatus = 'ERROR'; + } + $.write(settings, SETTINGS_KEY); + } +} diff --git a/backend/src/restful/sort.js b/backend/src/restful/sort.js new file mode 100644 index 0000000000..03240e05f6 --- /dev/null +++ b/backend/src/restful/sort.js @@ -0,0 +1,49 @@ +import { + ARTIFACTS_KEY, + COLLECTIONS_KEY, + SUBS_KEY, + FILES_KEY, +} from '@/constants'; +import $ from '@/core/app'; +import { success } from '@/restful/response'; + +export default function register($app) { + $app.post('/api/sort/subs', sortSubs); + $app.post('/api/sort/collections', sortCollections); + $app.post('/api/sort/artifacts', sortArtifacts); + $app.post('/api/sort/files', sortFiles); +} + +function sortSubs(req, res) { + const orders = req.body; + const allSubs = $.read(SUBS_KEY); + allSubs.sort((a, b) => orders.indexOf(a.name) - orders.indexOf(b.name)); + $.write(allSubs, SUBS_KEY); + success(res, allSubs); +} + +function sortCollections(req, res) { + const orders = req.body; + const allCols = $.read(COLLECTIONS_KEY); + allCols.sort((a, b) => orders.indexOf(a.name) - orders.indexOf(b.name)); + $.write(allCols, COLLECTIONS_KEY); + success(res, allCols); +} + +function sortArtifacts(req, res) { + const orders = req.body; + const allArtifacts = $.read(ARTIFACTS_KEY); + allArtifacts.sort( + (a, b) => orders.indexOf(a.name) - orders.indexOf(b.name), + ); + $.write(allArtifacts, ARTIFACTS_KEY); + success(res, allArtifacts); +} + +function sortFiles(req, res) { + const orders = req.body; + const allFiles = $.read(FILES_KEY); + allFiles.sort((a, b) => orders.indexOf(a.name) - orders.indexOf(b.name)); + $.write(allFiles, FILES_KEY); + success(res, allFiles); +} diff --git a/backend/src/restful/subscriptions.js b/backend/src/restful/subscriptions.js new file mode 100644 index 0000000000..0e6d363fd8 --- /dev/null +++ b/backend/src/restful/subscriptions.js @@ -0,0 +1,386 @@ +import { + NetworkError, + InternalServerError, + ResourceNotFoundError, + RequestInvalidError, +} from './errors'; +import { deleteByName, findByName, updateByName } from '@/utils/database'; +import { + SUBS_KEY, + COLLECTIONS_KEY, + ARTIFACTS_KEY, + FILES_KEY, +} from '@/constants'; +import { + getFlowHeaders, + parseFlowHeaders, + getRmainingDays, +} from '@/utils/flow'; +import { success, failed } from './response'; +import $ from '@/core/app'; +import { formatDateTime } from '@/utils'; + +if (!$.read(SUBS_KEY)) $.write({}, SUBS_KEY); + +export default function register($app) { + $app.get('/api/sub/flow/:name', getFlowInfo); + + $app.route('/api/sub/:name') + .get(getSubscription) + .patch(updateSubscription) + .delete(deleteSubscription); + + $app.route('/api/subs') + .get(getAllSubscriptions) + .post(createSubscription) + .put(replaceSubscriptions); +} + +// subscriptions API +async function getFlowInfo(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + let { url } = req.query; + if (url) { + url = decodeURIComponent(url); + $.info(`指定远程订阅 URL: ${url}`); + } + const allSubs = $.read(SUBS_KEY); + const sub = findByName(allSubs, name); + if (!sub) { + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `Subscription ${name} does not exist!`, + ), + 404, + ); + return; + } + if ( + sub.source === 'local' && + !['localFirst', 'remoteFirst'].includes(sub.mergeSources) + ) { + if (sub.subUserinfo) { + let subUserInfo; + if (/^https?:\/\//.test(sub.subUserinfo)) { + try { + subUserInfo = await getFlowHeaders( + undefined, + undefined, + undefined, + sub.proxy, + sub.subUserinfo, + ); + } catch (e) { + $.error( + `订阅 ${name} 使用自定义流量链接 ${ + sub.subUserinfo + } 获取流量信息时发生错误: ${JSON.stringify(e)}`, + ); + } + } else { + subUserInfo = sub.subUserinfo; + } + try { + success(res, { + ...parseFlowHeaders(subUserInfo), + }); + } catch (e) { + $.error( + `Failed to parse flow info for local subscription ${name}: ${ + e.message ?? e + }`, + ); + failed( + res, + new RequestInvalidError( + 'NO_FLOW_INFO', + 'N/A', + `Failed to parse flow info`, + ), + ); + } + } else { + failed( + res, + new RequestInvalidError( + 'NO_FLOW_INFO', + 'N/A', + `Local subscription ${name} has no flow information!`, + ), + ); + } + return; + } + try { + url = + `${url || sub.url}` + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length)?.[0] || ''; + + let $arguments = {}; + const rawArgs = url.split('#'); + url = url.split('#')[0]; + if (rawArgs.length > 1) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $arguments = JSON.parse(decodeURIComponent(rawArgs[1])); + } catch (e) { + for (const pair of rawArgs[1].split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $arguments[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + } + if ($arguments.noFlow) { + failed( + res, + new RequestInvalidError( + 'NO_FLOW_INFO', + 'N/A', + `Subscription ${name}: noFlow`, + ), + ); + return; + } + const flowHeaders = await getFlowHeaders( + $arguments?.insecure ? `${url}#insecure` : url, + $arguments.flowUserAgent, + undefined, + sub.proxy, + $arguments.flowUrl, + ); + if (!flowHeaders && !sub.subUserinfo) { + failed( + res, + new InternalServerError( + 'NO_FLOW_INFO', + 'No flow info', + `Failed to fetch flow headers`, + ), + ); + return; + } + try { + const remainingDays = getRmainingDays({ + resetDay: $arguments.resetDay, + startDate: $arguments.startDate, + cycleDays: $arguments.cycleDays, + }); + let subUserInfo; + if (/^https?:\/\//.test(sub.subUserinfo)) { + try { + subUserInfo = await getFlowHeaders( + undefined, + undefined, + undefined, + sub.proxy, + sub.subUserinfo, + ); + } catch (e) { + $.error( + `订阅 ${name} 使用自定义流量链接 ${ + sub.subUserinfo + } 获取流量信息时发生错误: ${JSON.stringify(e)}`, + ); + } + } else { + subUserInfo = sub.subUserinfo; + } + const result = { + ...parseFlowHeaders( + [subUserInfo, flowHeaders].filter((i) => i).join('; '), + ), + }; + if (remainingDays != null) { + result.remainingDays = remainingDays; + } + success(res, result); + } catch (e) { + $.error( + `Failed to parse flow info for local subscription ${name}: ${ + e.message ?? e + }`, + ); + failed( + res, + new RequestInvalidError( + 'NO_FLOW_INFO', + 'N/A', + `Failed to parse flow info`, + ), + ); + } + } catch (err) { + failed( + res, + new NetworkError( + `URL_NOT_ACCESSIBLE`, + `The URL for subscription ${name} is inaccessible.`, + ), + ); + } +} + +function createSubscription(req, res) { + const sub = req.body; + $.info(`正在创建订阅: ${sub.name}`); + if (/\//.test(sub.name)) { + failed( + res, + new RequestInvalidError( + 'INVALID_NAME', + `Subscription ${sub.name} is invalid`, + ), + ); + return; + } + const allSubs = $.read(SUBS_KEY); + if (findByName(allSubs, sub.name)) { + failed( + res, + new RequestInvalidError( + 'DUPLICATE_KEY', + `Subscription ${sub.name} already exists.`, + ), + ); + return; + } + allSubs.push(sub); + $.write(allSubs, SUBS_KEY); + success(res, sub, 201); +} + +function getSubscription(req, res) { + let { name } = req.params; + let { raw } = req.query; + name = decodeURIComponent(name); + const allSubs = $.read(SUBS_KEY); + const sub = findByName(allSubs, name); + if (sub) { + if (raw) { + res.set('content-type', 'application/json') + .set( + 'content-disposition', + `attachment; filename="${encodeURIComponent( + `sub-store_subscription_${name}_${formatDateTime( + new Date(), + )}.json`, + )}"`, + ) + .send(JSON.stringify(sub)); + } else { + success(res, sub); + } + } else { + failed( + res, + new ResourceNotFoundError( + `SUBSCRIPTION_NOT_FOUND`, + `Subscription ${name} does not exist`, + 404, + ), + ); + } +} + +function updateSubscription(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); // the original name + let sub = req.body; + const allSubs = $.read(SUBS_KEY); + const oldSub = findByName(allSubs, name); + if (oldSub) { + const newSub = { + ...oldSub, + ...sub, + }; + $.info(`正在更新订阅: ${name}`); + // allow users to update the subscription name + if (name !== sub.name) { + // update all collections refer to this name + const allCols = $.read(COLLECTIONS_KEY) || []; + for (const collection of allCols) { + const idx = collection.subscriptions.indexOf(name); + if (idx !== -1) { + collection.subscriptions[idx] = sub.name; + } + } + + // update all artifacts referring this subscription + const allArtifacts = $.read(ARTIFACTS_KEY) || []; + for (const artifact of allArtifacts) { + if ( + artifact.type === 'subscription' && + artifact.source == name + ) { + artifact.source = sub.name; + } + } + // update all files referring this subscription + const allFiles = $.read(FILES_KEY) || []; + for (const file of allFiles) { + if ( + file.sourceType === 'subscription' && + file.sourceName == name + ) { + file.sourceName = sub.name; + } + } + + $.write(allCols, COLLECTIONS_KEY); + $.write(allArtifacts, ARTIFACTS_KEY); + $.write(allFiles, FILES_KEY); + } + updateByName(allSubs, name, newSub); + $.write(allSubs, SUBS_KEY); + success(res, newSub); + } else { + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `Subscription ${name} does not exist!`, + ), + 404, + ); + } +} + +function deleteSubscription(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + $.info(`删除订阅:${name}...`); + // delete from subscriptions + let allSubs = $.read(SUBS_KEY); + deleteByName(allSubs, name); + $.write(allSubs, SUBS_KEY); + // delete from collections + const allCols = $.read(COLLECTIONS_KEY); + for (const collection of allCols) { + collection.subscriptions = collection.subscriptions.filter( + (s) => s !== name, + ); + } + $.write(allCols, COLLECTIONS_KEY); + success(res); +} + +function getAllSubscriptions(req, res) { + const allSubs = $.read(SUBS_KEY); + success(res, allSubs); +} + +function replaceSubscriptions(req, res) { + const allSubs = req.body; + $.write(allSubs, SUBS_KEY); + success(res); +} diff --git a/backend/src/restful/sync.js b/backend/src/restful/sync.js new file mode 100644 index 0000000000..899e52d83a --- /dev/null +++ b/backend/src/restful/sync.js @@ -0,0 +1,894 @@ +import $ from '@/core/app'; +import { + ARTIFACTS_KEY, + COLLECTIONS_KEY, + RULES_KEY, + SUBS_KEY, + FILES_KEY, +} from '@/constants'; +import { failed, success } from '@/restful/response'; +import { InternalServerError, ResourceNotFoundError } from '@/restful/errors'; +import { findByName } from '@/utils/database'; +import download from '@/utils/download'; +import { ProxyUtils } from '@/core/proxy-utils'; +import { RuleUtils } from '@/core/rule-utils'; +import { syncToGist } from '@/restful/artifacts'; + +export default function register($app) { + // Initialization + if (!$.read(ARTIFACTS_KEY)) $.write({}, ARTIFACTS_KEY); + + // sync all artifacts + $app.get('/api/sync/artifacts', syncAllArtifacts); + $app.get('/api/sync/artifact/:name', syncArtifact); +} + +async function produceArtifact({ + type, + name, + platform, + url, + ua, + content, + mergeSources, + ignoreFailedRemoteSub, + ignoreFailedRemoteFile, + produceType, + produceOpts = {}, + subscription, + awaitCustomCache, + $options, + proxy, + noCache, +}) { + platform = platform || 'JSON'; + + if (['subscription', 'sub'].includes(type)) { + let sub; + if (name) { + const allSubs = $.read(SUBS_KEY); + sub = findByName(allSubs, name); + if (!sub) throw new Error(`找不到订阅 ${name}`); + } else if (subscription) { + sub = subscription; + } else { + throw new Error('未提供订阅名称或订阅数据'); + } + let raw; + if (content && !['localFirst', 'remoteFirst'].includes(mergeSources)) { + raw = content; + } else if (url) { + const errors = {}; + raw = await Promise.all( + url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + ua || sub.ua, + undefined, + proxy || sub.proxy, + undefined, + awaitCustomCache, + noCache || sub.noCache, + true, + ); + } catch (err) { + errors[url] = err; + $.error( + `订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + let subIgnoreFailedRemoteSub = sub.ignoreFailedRemoteSub; + if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') { + subIgnoreFailedRemoteSub = ignoreFailedRemoteSub; + } + + if (Object.keys(errors).length > 0) { + if (!subIgnoreFailedRemoteSub) { + throw new Error( + `订阅 ${sub.name} 的远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } else if (subIgnoreFailedRemoteSub === 'enabled') { + $.notify( + `🌍 Sub-Store 处理订阅失败`, + `❌ ${sub.name}`, + `远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + if (mergeSources === 'localFirst') { + raw.unshift(content); + } else if (mergeSources === 'remoteFirst') { + raw.push(content); + } + } else if ( + sub.source === 'local' && + !['localFirst', 'remoteFirst'].includes(sub.mergeSources) + ) { + raw = sub.content; + } else { + const errors = {}; + raw = await Promise.all( + sub.url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + ua || sub.ua, + undefined, + proxy || sub.proxy, + undefined, + awaitCustomCache, + noCache || sub.noCache, + true, + ); + } catch (err) { + errors[url] = err; + $.error( + `订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + let subIgnoreFailedRemoteSub = sub.ignoreFailedRemoteSub; + if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') { + subIgnoreFailedRemoteSub = ignoreFailedRemoteSub; + } + + if (Object.keys(errors).length > 0) { + if (!subIgnoreFailedRemoteSub) { + throw new Error( + `订阅 ${sub.name} 的远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } else if (subIgnoreFailedRemoteSub === 'enabled') { + $.notify( + `🌍 Sub-Store 处理订阅失败`, + `❌ ${sub.name}`, + `远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + if (sub.mergeSources === 'localFirst') { + raw.unshift(sub.content); + } else if (sub.mergeSources === 'remoteFirst') { + raw.push(sub.content); + } + } + // parse proxies + let proxies = (Array.isArray(raw) ? raw : [raw]) + .map((i) => ProxyUtils.parse(i)) + .flat(); + + proxies.forEach((proxy) => { + proxy._subName = sub.name; + proxy._subDisplayName = sub.displayName; + }); + // apply processors + proxies = await ProxyUtils.process( + proxies, + sub.process || [], + platform, + { [sub.name]: sub }, + $options, + ); + if (proxies.length === 0) { + throw new Error(`订阅 ${name} 中不含有效节点`); + } + // check duplicate + const exist = {}; + for (const proxy of proxies) { + if (exist[proxy.name]) { + $.notify( + '🌍 Sub-Store', + `⚠️ 订阅 ${name} 包含重复节点 ${proxy.name}!`, + '请仔细检测配置!', + { + 'media-url': + 'https://cdn3.iconfinder.com/data/icons/seo-outline-1/512/25_code_program_programming_develop_bug_search_developer-512.png', + }, + ); + break; + } + exist[proxy.name] = true; + } + // produce + return ProxyUtils.produce(proxies, platform, produceType, produceOpts); + } else if (['collection', 'col'].includes(type)) { + const allSubs = $.read(SUBS_KEY); + const allCols = $.read(COLLECTIONS_KEY); + const collection = findByName(allCols, name); + if (!collection) throw new Error(`找不到组合订阅 ${name}`); + const subnames = [...collection.subscriptions]; + let subscriptionTags = collection.subscriptionTags; + if (Array.isArray(subscriptionTags) && subscriptionTags.length > 0) { + allSubs.forEach((sub) => { + if ( + Array.isArray(sub.tag) && + sub.tag.length > 0 && + !subnames.includes(sub.name) && + sub.tag.some((tag) => subscriptionTags.includes(tag)) + ) { + subnames.push(sub.name); + } + }); + } + const results = {}; + const errors = {}; + let processed = 0; + + await Promise.all( + subnames.map(async (name) => { + const sub = findByName(allSubs, name); + const passThroughUA = sub.passThroughUA; + let reqUA = sub.ua; + if (passThroughUA) { + $.info( + `订阅开启了透传 User-Agent, 使用请求的 User-Agent: ${ua}`, + ); + reqUA = ua; + } + try { + $.info(`正在处理子订阅:${sub.name}...`); + let raw; + if ( + sub.source === 'local' && + !['localFirst', 'remoteFirst'].includes( + sub.mergeSources, + ) + ) { + raw = sub.content; + } else { + const errors = {}; + raw = await await Promise.all( + sub.url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + reqUA, + undefined, + proxy || + sub.proxy || + collection.proxy, + undefined, + undefined, + noCache || sub.noCache, + true, + ); + } catch (err) { + errors[url] = err; + $.error( + `订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + + if (Object.keys(errors).length > 0) { + if (!sub.ignoreFailedRemoteSub) { + throw new Error( + `订阅 ${sub.name} 的远程订阅 ${Object.keys( + errors, + ).join(', ')} 发生错误, 请查看日志`, + ); + } else if ( + sub.ignoreFailedRemoteSub === 'enabled' + ) { + $.notify( + `🌍 Sub-Store 处理订阅失败`, + `❌ ${sub.name}`, + `远程订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + if (sub.mergeSources === 'localFirst') { + raw.unshift(sub.content); + } else if (sub.mergeSources === 'remoteFirst') { + raw.push(sub.content); + } + } + // parse proxies + let currentProxies = (Array.isArray(raw) ? raw : [raw]) + .map((i) => ProxyUtils.parse(i)) + .flat(); + + currentProxies.forEach((proxy) => { + proxy._subName = sub.name; + proxy._subDisplayName = sub.displayName; + proxy._collectionName = collection.name; + proxy._collectionDisplayName = collection.displayName; + }); + + // apply processors + currentProxies = await ProxyUtils.process( + currentProxies, + sub.process || [], + platform, + { + [sub.name]: sub, + _collection: collection, + $options, + }, + ); + results[name] = currentProxies; + processed++; + $.info( + `✅ 子订阅:${sub.name}加载成功,进度--${ + 100 * (processed / subnames.length).toFixed(1) + }% `, + ); + } catch (err) { + processed++; + errors[name] = err; + $.error( + `❌ 处理组合订阅中的子订阅: ${ + sub.name + }时出现错误:${err}!进度--${ + 100 * (processed / subnames.length).toFixed(1) + }%`, + ); + } + }), + ); + let collectionIgnoreFailedRemoteSub = collection.ignoreFailedRemoteSub; + if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') { + collectionIgnoreFailedRemoteSub = ignoreFailedRemoteSub; + } + + if (Object.keys(errors).length > 0) { + if (!collectionIgnoreFailedRemoteSub) { + throw new Error( + `组合订阅 ${collection.name} 的子订阅 ${Object.keys( + errors, + ).join(', ')} 发生错误, 请查看日志`, + ); + } else if (collectionIgnoreFailedRemoteSub === 'enabled') { + $.notify( + `🌍 Sub-Store 处理组合订阅失败`, + `❌ ${collection.name}`, + `子订阅 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + + // merge proxies with the original order + let proxies = Array.prototype.concat.apply( + [], + subnames.map((name) => results[name] || []), + ); + + proxies.forEach((proxy) => { + proxy._collectionName = collection.name; + proxy._collectionDisplayName = collection.displayName; + }); + + // apply own processors + proxies = await ProxyUtils.process( + proxies, + collection.process || [], + platform, + { _collection: collection }, + $options, + ); + if (proxies.length === 0) { + throw new Error(`组合订阅 ${name} 中不含有效节点`); + } + // check duplicate + const exist = {}; + for (const proxy of proxies) { + if (exist[proxy.name]) { + $.notify( + '🌍 Sub-Store', + `⚠️ 组合订阅 ${name} 包含重复节点 ${proxy.name}!`, + '请仔细检测配置!', + { + 'media-url': + 'https://cdn3.iconfinder.com/data/icons/seo-outline-1/512/25_code_program_programming_develop_bug_search_developer-512.png', + }, + ); + break; + } + exist[proxy.name] = true; + } + return ProxyUtils.produce(proxies, platform, produceType, produceOpts); + } else if (type === 'rule') { + const allRules = $.read(RULES_KEY); + const rule = findByName(allRules, name); + if (!rule) throw new Error(`找不到规则 ${name}`); + let rules = []; + for (let i = 0; i < rule.urls.length; i++) { + const url = rule.urls[i]; + $.info( + `正在处理URL:${url},进度--${ + 100 * ((i + 1) / rule.urls.length).toFixed(1) + }% `, + ); + try { + const { body } = await download(url); + const currentRules = RuleUtils.parse(body); + rules = rules.concat(currentRules); + } catch (err) { + $.error( + `处理分流订阅中的URL: ${url}时出现错误:${err}! 该订阅已被跳过。`, + ); + } + } + // remove duplicates + rules = await RuleUtils.process(rules, [ + { type: 'Remove Duplicate Filter' }, + ]); + // produce output + return RuleUtils.produce(rules, platform); + } else if (type === 'file') { + const allFiles = $.read(FILES_KEY); + const file = findByName(allFiles, name); + if (!file) throw new Error(`找不到文件 ${name}`); + let raw = ''; + if (file.type !== 'mihomoProfile') { + if ( + content && + !['localFirst', 'remoteFirst'].includes(mergeSources) + ) { + raw = content; + } else if (url) { + const errors = {}; + raw = await Promise.all( + url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + ua || file.ua, + undefined, + file.proxy || proxy, + undefined, + undefined, + noCache, + ); + } catch (err) { + errors[url] = err; + $.error( + `文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + let fileIgnoreFailedRemoteFile = file.ignoreFailedRemoteFile; + if ( + ignoreFailedRemoteFile != null && + ignoreFailedRemoteFile !== '' + ) { + fileIgnoreFailedRemoteFile = ignoreFailedRemoteFile; + } + if ( + !fileIgnoreFailedRemoteFile && + Object.keys(errors).length > 0 + ) { + throw new Error( + `文件 ${file.name} 的远程文件 ${Object.keys( + errors, + ).join(', ')} 发生错误, 请查看日志`, + ); + } + if (mergeSources === 'localFirst') { + raw.unshift(content); + } else if (mergeSources === 'remoteFirst') { + raw.push(content); + } + } else if ( + file.source === 'local' && + !['localFirst', 'remoteFirst'].includes(file.mergeSources) + ) { + raw = file.content; + } else { + const errors = {}; + raw = await Promise.all( + file.url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length) + .map(async (url) => { + try { + return await download( + url, + ua || file.ua, + undefined, + file.proxy || proxy, + undefined, + undefined, + noCache, + ); + } catch (err) { + errors[url] = err; + $.error( + `文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`, + ); + return ''; + } + }), + ); + let fileIgnoreFailedRemoteFile = file.ignoreFailedRemoteFile; + if ( + ignoreFailedRemoteFile != null && + ignoreFailedRemoteFile !== '' + ) { + fileIgnoreFailedRemoteFile = ignoreFailedRemoteFile; + } + + if (Object.keys(errors).length > 0) { + if (!fileIgnoreFailedRemoteFile) { + throw new Error( + `文件 ${file.name} 的远程文件 ${Object.keys( + errors, + ).join(', ')} 发生错误, 请查看日志`, + ); + } else if (fileIgnoreFailedRemoteFile === 'enabled') { + $.notify( + `🌍 Sub-Store 处理文件失败`, + `❌ ${file.name}`, + `远程文件 ${Object.keys(errors).join( + ', ', + )} 发生错误, 请查看日志`, + ); + } + } + if (file.mergeSources === 'localFirst') { + raw.unshift(file.content); + } else if (file.mergeSources === 'remoteFirst') { + raw.push(file.content); + } + } + } + const files = (Array.isArray(raw) ? raw : [raw]).flat(); + let filesContent = files + .filter((i) => i != null && i !== '') + .join('\n'); + + // apply processors + const processed = + Array.isArray(file.process) && file.process.length > 0 + ? await ProxyUtils.process( + { + $files: files, + $content: filesContent, + $options, + $file: file, + }, + file.process, + ) + : { $content: filesContent, $files: files, $options }; + + return processed?.$content ?? ''; + } +} + +async function syncArtifacts() { + $.info('开始同步所有远程配置...'); + const allArtifacts = $.read(ARTIFACTS_KEY); + const files = {}; + + try { + const valid = []; + const invalid = []; + const allSubs = $.read(SUBS_KEY); + const allCols = $.read(COLLECTIONS_KEY); + const subNames = []; + let enabledCount = 0; + allArtifacts.map((artifact) => { + if (artifact.sync && artifact.source) { + enabledCount++; + if (artifact.type === 'subscription') { + const subName = artifact.source; + const sub = findByName(allSubs, subName); + if (sub && sub.url && !subNames.includes(subName)) { + subNames.push(subName); + } + } else if (artifact.type === 'collection') { + const collection = findByName(allCols, artifact.source); + if (collection && Array.isArray(collection.subscriptions)) { + collection.subscriptions.map((subName) => { + const sub = findByName(allSubs, subName); + if (sub && sub.url && !subNames.includes(subName)) { + subNames.push(subName); + } + }); + } + } + } + }); + + if (enabledCount === 0) { + $.info( + `需同步的配置: ${enabledCount}, 总数: ${allArtifacts.length}`, + ); + return; + } + + if (subNames.length > 0) { + await Promise.all( + subNames.map(async (subName) => { + try { + await produceArtifact({ + type: 'subscription', + name: subName, + awaitCustomCache: true, + }); + } catch (e) { + // $.error(`${e.message ?? e}`); + } + }), + ); + } + + await Promise.all( + allArtifacts.map(async (artifact) => { + try { + if (artifact.sync && artifact.source) { + $.info(`正在同步云配置:${artifact.name}...`); + + const useMihomoExternal = + artifact.platform === 'SurgeMac'; + + if (useMihomoExternal) { + $.info( + `手动指定了 target 为 SurgeMac, 将使用 Mihomo External`, + ); + } + + const output = await produceArtifact({ + type: artifact.type, + name: artifact.source, + platform: artifact.platform, + produceOpts: { + 'include-unsupported-proxy': + artifact.includeUnsupportedProxy, + useMihomoExternal, + }, + }); + + // if (!output || output.length === 0) + // throw new Error('该配置的结果为空 不进行上传'); + + files[encodeURIComponent(artifact.name)] = { + content: output, + }; + + valid.push(artifact.name); + } + } catch (e) { + $.error( + `生成同步配置 ${artifact.name} 发生错误: ${ + e.message ?? e + }`, + ); + invalid.push(artifact.name); + } + }), + ); + + $.info(`${valid.length} 个同步配置生成成功: ${valid.join(', ')}`); + $.info(`${invalid.length} 个同步配置生成失败: ${invalid.join(', ')}`); + + if (valid.length === 0) { + throw new Error( + `同步配置 ${invalid.join(', ')} 生成失败 详情请查看日志`, + ); + } + + const resp = await syncToGist(files); + const body = JSON.parse(resp.body); + + delete body.history; + delete body.forks; + delete body.owner; + Object.values(body.files).forEach((file) => { + delete file.content; + }); + $.info('上传配置响应:'); + $.info(JSON.stringify(body, null, 2)); + + for (const artifact of allArtifacts) { + if ( + artifact.sync && + artifact.source && + valid.includes(artifact.name) + ) { + artifact.updated = new Date().getTime(); + // extract real url from gist + let files = body.files; + let isGitLab; + if (Array.isArray(files)) { + isGitLab = true; + files = Object.fromEntries( + files.map((item) => [item.path, item]), + ); + } + const raw_url = + files[encodeURIComponent(artifact.name)]?.raw_url; + const new_url = isGitLab + ? raw_url + : raw_url?.replace(/\/raw\/[^/]*\/(.*)/, '/raw/$1'); + $.info( + `上传配置完成\n文件列表: ${Object.keys(files).join( + ', ', + )}\n当前文件: ${encodeURIComponent( + artifact.name, + )}\n响应返回的原始链接: ${raw_url}\n处理完的新链接: ${new_url}`, + ); + artifact.url = new_url; + } + } + + $.write(allArtifacts, ARTIFACTS_KEY); + $.info('上传配置成功'); + + if (invalid.length > 0) { + throw new Error( + `同步配置成功 ${valid.length} 个, 失败 ${invalid.length} 个, 详情请查看日志`, + ); + } else { + $.info(`同步配置成功 ${valid.length} 个`); + } + } catch (e) { + $.error(`同步配置失败,原因:${e.message ?? e}`); + throw e; + } +} +async function syncAllArtifacts(_, res) { + $.info('开始同步所有远程配置...'); + try { + await syncArtifacts(); + success(res); + } catch (e) { + $.error(`同步配置失败,原因:${e.message ?? e}`); + failed( + res, + new InternalServerError( + `FAILED_TO_SYNC_ARTIFACTS`, + `Failed to sync all artifacts`, + `Reason: ${e.message ?? e}`, + ), + ); + } +} + +async function syncArtifact(req, res) { + let { name } = req.params; + name = decodeURIComponent(name); + $.info(`开始同步远程配置 ${name}...`); + const allArtifacts = $.read(ARTIFACTS_KEY); + const artifact = findByName(allArtifacts, name); + + if (!artifact) { + $.error(`找不到远程配置 ${name}`); + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_NOT_FOUND', + `找不到远程配置 ${name}`, + ), + 404, + ); + return; + } + + if (!artifact.source) { + $.error(`远程配置 ${name} 未设置来源`); + failed( + res, + new ResourceNotFoundError( + 'RESOURCE_HAS_NO_SOURCE', + `远程配置 ${name} 未设置来源`, + ), + 404, + ); + return; + } + + try { + const useMihomoExternal = artifact.platform === 'SurgeMac'; + + if (useMihomoExternal) { + $.info(`手动指定了 target 为 SurgeMac, 将使用 Mihomo External`); + } + const output = await produceArtifact({ + type: artifact.type, + name: artifact.source, + platform: artifact.platform, + produceOpts: { + 'include-unsupported-proxy': artifact.includeUnsupportedProxy, + useMihomoExternal, + }, + }); + + $.info( + `正在上传配置:${artifact.name}\n>>>${JSON.stringify( + artifact, + null, + 2, + )}`, + ); + // if (!output || output.length === 0) + // throw new Error('该配置的结果为空 不进行上传'); + const resp = await syncToGist({ + [encodeURIComponent(artifact.name)]: { + content: output, + }, + }); + artifact.updated = new Date().getTime(); + const body = JSON.parse(resp.body); + + delete body.history; + delete body.forks; + delete body.owner; + Object.values(body.files).forEach((file) => { + delete file.content; + }); + $.info('上传配置响应:'); + $.info(JSON.stringify(body, null, 2)); + + let files = body.files; + let isGitLab; + if (Array.isArray(files)) { + isGitLab = true; + files = Object.fromEntries(files.map((item) => [item.path, item])); + } + const raw_url = files[encodeURIComponent(artifact.name)]?.raw_url; + const new_url = isGitLab + ? raw_url + : raw_url?.replace(/\/raw\/[^/]*\/(.*)/, '/raw/$1'); + $.info( + `上传配置完成\n文件列表: ${Object.keys(files).join( + ', ', + )}\n当前文件: ${encodeURIComponent( + artifact.name, + )}\n响应返回的原始链接: ${raw_url}\n处理完的新链接: ${new_url}`, + ); + artifact.url = new_url; + $.write(allArtifacts, ARTIFACTS_KEY); + success(res, artifact); + } catch (err) { + $.error(`远程配置 ${artifact.name} 发生错误: ${err.message ?? err}`); + failed( + res, + new InternalServerError( + `FAILED_TO_SYNC_ARTIFACT`, + `Failed to sync artifact ${name}`, + `Reason: ${err}`, + ), + ); + } +} + +export { produceArtifact, syncArtifacts }; diff --git a/backend/src/restful/token.js b/backend/src/restful/token.js new file mode 100644 index 0000000000..deb3f83ec5 --- /dev/null +++ b/backend/src/restful/token.js @@ -0,0 +1,181 @@ +import { deleteByName } from '@/utils/database'; +import { ENV } from '@/vendor/open-api'; +import { TOKENS_KEY, SUBS_KEY, FILES_KEY, COLLECTIONS_KEY } from '@/constants'; +import { failed, success } from '@/restful/response'; +import $ from '@/core/app'; +import { RequestInvalidError, InternalServerError } from '@/restful/errors'; + +export default function register($app) { + if (!$.read(TOKENS_KEY)) $.write([], TOKENS_KEY); + + $app.post('/api/token', signToken); + + $app.route('/api/token/:token').delete(deleteToken); + + $app.route('/api/tokens').get(getAllTokens); +} + +function deleteToken(req, res) { + let { token } = req.params; + token = decodeURIComponent(token); + $.info(`正在删除:${token}`); + let allTokens = $.read(TOKENS_KEY); + deleteByName(allTokens, token, 'token'); + $.write(allTokens, TOKENS_KEY); + success(res); +} + +function getAllTokens(req, res) { + const { type, name } = req.query; + const allTokens = $.read(TOKENS_KEY) || []; + success( + res, + type || name + ? allTokens.filter( + (item) => + (type ? item.type === type : true) && + (name ? item.name === name : true), + ) + : allTokens, + ); +} + +async function signToken(req, res) { + if (!ENV().isNode) { + return failed( + res, + new RequestInvalidError( + 'INVALID_ENV', + `This endpoint is only available in Node.js environment`, + ), + ); + } + try { + const { payload, options } = req.body; + const ms = eval(`require("ms")`); + let token = payload?.token; + if (token != null) { + if (typeof token !== 'string' || token.length < 1) { + return failed( + res, + new RequestInvalidError( + 'INVALID_CUSTOM_TOKEN', + `Invalid custom token: ${token}`, + ), + ); + } + const tokens = $.read(TOKENS_KEY) || []; + if (tokens.find((t) => t.token === token)) { + return failed( + res, + new RequestInvalidError( + 'DUPLICATE_TOKEN', + `Token ${token} already exists`, + ), + ); + } + } + const type = payload?.type; + const name = payload?.name; + if (!type || !name) + return failed( + res, + new RequestInvalidError( + 'INVALID_PAYLOAD', + `payload type and name are required`, + ), + ); + if (type === 'col') { + const collections = $.read(COLLECTIONS_KEY) || []; + const collection = collections.find((c) => c.name === name); + if (!collection) + return failed( + res, + new RequestInvalidError( + 'INVALID_COLLECTION', + `collection ${name} not found`, + ), + ); + } else if (type === 'file') { + const files = $.read(FILES_KEY) || []; + const file = files.find((f) => f.name === name); + if (!file) + return failed( + res, + new RequestInvalidError( + 'INVALID_FILE', + `file ${name} not found`, + ), + ); + } else if (type === 'sub') { + const subs = $.read(SUBS_KEY) || []; + const sub = subs.find((s) => s.name === name); + if (!sub) + return failed( + res, + new RequestInvalidError( + 'INVALID_SUB', + `sub ${name} not found`, + ), + ); + } else { + return failed( + res, + new RequestInvalidError( + 'INVALID_TYPE', + `type ${name} not supported`, + ), + ); + } + let expiresIn = options?.expiresIn; + if (options?.expiresIn != null) { + expiresIn = ms(options.expiresIn); + if (expiresIn == null || isNaN(expiresIn) || expiresIn <= 0) { + return failed( + res, + new RequestInvalidError( + 'INVALID_EXPIRES_IN', + `Invalid expiresIn option: ${options.expiresIn}`, + ), + ); + } + } + // const secret = eval('process.env.SUB_STORE_FRONTEND_BACKEND_PATH'); + const nanoid = eval(`require("nanoid")`); + const tokens = $.read(TOKENS_KEY) || []; + // const now = Date.now(); + // for (const key in tokens) { + // const token = tokens[key]; + // if (token.exp != null || token.exp < now) { + // delete tokens[key]; + // } + // } + if (!token) { + do { + token = nanoid.customAlphabet(nanoid.urlAlphabet)(); + } while (tokens.find((t) => t.token === token)); + } + tokens.push({ + ...payload, + token, + createdAt: Date.now(), + expiresIn: expiresIn > 0 ? options?.expiresIn : undefined, + exp: expiresIn > 0 ? Date.now() + expiresIn : undefined, + }); + + $.write(tokens, TOKENS_KEY); + return success(res, { + token, + // secret, + }); + } catch (e) { + return failed( + res, + new InternalServerError( + 'TOKEN_SIGN_FAILED', + `Failed to sign token`, + `Reason: ${e.message ?? e}`, + ), + ); + } +} diff --git a/backend/src/test/proxy-parsers/loon.spec.js b/backend/src/test/proxy-parsers/loon.spec.js new file mode 100644 index 0000000000..37c1ca8226 --- /dev/null +++ b/backend/src/test/proxy-parsers/loon.spec.js @@ -0,0 +1,144 @@ +import getLoonParser from '@/core/proxy-utils/parsers/peggy/loon'; +import { describe, it } from 'mocha'; +import testcases from './testcases'; +import { expect } from 'chai'; + +const parser = getLoonParser(); + +describe('Loon', function () { + describe('shadowsocks', function () { + it('test shadowsocks simple', function () { + const { input, expected } = testcases.SS.SIMPLE; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + it('test shadowsocks obfs + tls', function () { + const { input, expected } = testcases.SS.OBFS_TLS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + it('test shadowsocks obfs + http', function () { + const { input, expected } = testcases.SS.OBFS_HTTP; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + }); + + describe('shadowsocksr', function () { + it('test shadowsocksr simple', function () { + const { input, expected } = testcases.SSR.SIMPLE; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + }); + + describe('trojan', function () { + it('test trojan simple', function () { + const { input, expected } = testcases.TROJAN.SIMPLE; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + + it('test trojan + ws', function () { + const { input, expected } = testcases.TROJAN.WS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + + it('test trojan + wss', function () { + const { input, expected } = testcases.TROJAN.WSS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + }); + + describe('vmess', function () { + it('test vmess simple', function () { + const { input, expected } = testcases.VMESS.SIMPLE; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vmess + aead', function () { + const { input, expected } = testcases.VMESS.AEAD; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vmess + ws', function () { + const { input, expected } = testcases.VMESS.WS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vmess + wss', function () { + const { input, expected } = testcases.VMESS.WSS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vmess + http', function () { + const { input, expected } = testcases.VMESS.HTTP; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vmess + http + tls', function () { + const { input, expected } = testcases.VMESS.HTTP_TLS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + }); + + describe('vless', function () { + it('test vless simple', function () { + const { input, expected } = testcases.VLESS.SIMPLE; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vless + ws', function () { + const { input, expected } = testcases.VLESS.WS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vless + wss', function () { + const { input, expected } = testcases.VLESS.WSS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vless + http', function () { + const { input, expected } = testcases.VLESS.HTTP; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + + it('test vless + http + tls', function () { + const { input, expected } = testcases.VLESS.HTTP_TLS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected.Loon); + }); + }); + + describe('http(s)', function () { + it('test http simple', function () { + const { input, expected } = testcases.HTTP.SIMPLE; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + + it('test http with authentication', function () { + const { input, expected } = testcases.HTTP.AUTH; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + + it('test https', function () { + const { input, expected } = testcases.HTTP.TLS; + const proxy = parser.parse(input.Loon); + expect(proxy).eql(expected); + }); + }); +}); diff --git a/backend/src/test/proxy-parsers/qx.spec.js b/backend/src/test/proxy-parsers/qx.spec.js new file mode 100644 index 0000000000..a6662fa3da --- /dev/null +++ b/backend/src/test/proxy-parsers/qx.spec.js @@ -0,0 +1,142 @@ +import getQXParser from '@/core/proxy-utils/parsers/peggy/qx'; +import { describe, it } from 'mocha'; +import testcases from './testcases'; +import { expect } from 'chai'; + +const parser = getQXParser(); + +describe('QX', function () { + describe('shadowsocks', function () { + it('test shadowsocks simple', function () { + const { input, expected } = testcases.SS.SIMPLE; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + it('test shadowsocks obfs + tls', function () { + const { input, expected } = testcases.SS.OBFS_TLS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + it('test shadowsocks obfs + http', function () { + const { input, expected } = testcases.SS.OBFS_HTTP; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + it('test shadowsocks v2ray-plugin + ws', function () { + const { input, expected } = testcases.SS.V2RAY_PLUGIN_WS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + it('test shadowsocks v2ray-plugin + wss', function () { + const { input, expected } = testcases.SS.V2RAY_PLUGIN_WSS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + }); + + describe('shadowsocksr', function () { + it('test shadowsocksr simple', function () { + const { input, expected } = testcases.SSR.SIMPLE; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + }); + + describe('trojan', function () { + it('test trojan simple', function () { + const { input, expected } = testcases.TROJAN.SIMPLE; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + + it('test trojan + ws', function () { + const { input, expected } = testcases.TROJAN.WS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + + it('test trojan + wss', function () { + const { input, expected } = testcases.TROJAN.WSS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + + it('test trojan + tls fingerprint', function () { + const { input, expected } = testcases.TROJAN.TLS_FINGERPRINT; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + }); + + describe('vmess', function () { + it('test vmess simple', function () { + const { input, expected } = testcases.VMESS.SIMPLE; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected.QX); + }); + + it('test vmess aead', function () { + const { input, expected } = testcases.VMESS.AEAD; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected.QX); + }); + + it('test vmess + ws', function () { + const { input, expected } = testcases.VMESS.WS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected.QX); + }); + + it('test vmess + wss', function () { + const { input, expected } = testcases.VMESS.WSS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected.QX); + }); + + it('test vmess + http', function () { + const { input, expected } = testcases.VMESS.HTTP; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected.QX); + }); + }); + + describe('http', function () { + it('test http simple', function () { + const { input, expected } = testcases.HTTP.SIMPLE; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + + it('test http with authentication', function () { + const { input, expected } = testcases.HTTP.AUTH; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + + it('test https', function () { + const { input, expected } = testcases.HTTP.TLS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + }); + + describe('socks5', function () { + it('test socks5 simple', function () { + const { input, expected } = testcases.SOCKS5.SIMPLE; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + + it('test socks5 with authentication', function () { + const { input, expected } = testcases.SOCKS5.AUTH; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + + it('test socks5 + tls', function () { + const { input, expected } = testcases.SOCKS5.TLS; + const proxy = parser.parse(input.QX); + expect(proxy).eql(expected); + }); + }); +}); diff --git a/backend/src/test/proxy-parsers/surge.spec.js b/backend/src/test/proxy-parsers/surge.spec.js new file mode 100644 index 0000000000..24819d33db --- /dev/null +++ b/backend/src/test/proxy-parsers/surge.spec.js @@ -0,0 +1,138 @@ +import getSurgeParser from '@/core/proxy-utils/parsers/peggy/surge'; +import { describe, it } from 'mocha'; +import testcases from './testcases'; +import { expect } from 'chai'; + +const parser = getSurgeParser(); + +describe('Surge', function () { + describe('shadowsocks', function () { + it('test shadowsocks simple', function () { + const { input, expected } = testcases.SS.SIMPLE; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + it('test shadowsocks obfs + tls', function () { + const { input, expected } = testcases.SS.OBFS_TLS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + it('test shadowsocks obfs + http', function () { + const { input, expected } = testcases.SS.OBFS_HTTP; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + }); + + describe('trojan', function () { + it('test trojan simple', function () { + const { input, expected } = testcases.TROJAN.SIMPLE; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test trojan + ws', function () { + const { input, expected } = testcases.TROJAN.WS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test trojan + wss', function () { + const { input, expected } = testcases.TROJAN.WSS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test trojan + tls fingerprint', function () { + const { input, expected } = testcases.TROJAN.TLS_FINGERPRINT; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + }); + + describe('vmess', function () { + it('test vmess simple', function () { + const { input, expected } = testcases.VMESS.SIMPLE; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected.Surge); + }); + + it('test vmess aead', function () { + const { input, expected } = testcases.VMESS.AEAD; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected.Surge); + }); + + it('test vmess + ws', function () { + const { input, expected } = testcases.VMESS.WS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected.Surge); + }); + + it('test vmess + wss', function () { + const { input, expected } = testcases.VMESS.WSS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected.Surge); + }); + }); + + describe('http', function () { + it('test http simple', function () { + const { input, expected } = testcases.HTTP.SIMPLE; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test http with authentication', function () { + const { input, expected } = testcases.HTTP.AUTH; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test https', function () { + const { input, expected } = testcases.HTTP.TLS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + }); + + describe('socks5', function () { + it('test socks5 simple', function () { + const { input, expected } = testcases.SOCKS5.SIMPLE; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test socks5 with authentication', function () { + const { input, expected } = testcases.SOCKS5.AUTH; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test socks5 + tls', function () { + const { input, expected } = testcases.SOCKS5.TLS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + }); + + describe('snell', function () { + it('test snell simple', function () { + const { input, expected } = testcases.SNELL.SIMPLE; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test snell obfs + http', function () { + const { input, expected } = testcases.SNELL.OBFS_HTTP; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + + it('test snell obfs + tls', function () { + const { input, expected } = testcases.SNELL.OBFS_TLS; + const proxy = parser.parse(input.Surge); + expect(proxy).eql(expected); + }); + }); +}); diff --git a/backend/src/test/proxy-parsers/testcases.js b/backend/src/test/proxy-parsers/testcases.js new file mode 100644 index 0000000000..863922951e --- /dev/null +++ b/backend/src/test/proxy-parsers/testcases.js @@ -0,0 +1,749 @@ +function createTestCases() { + const name = 'name'; + const server = 'example.com'; + const port = 10086; + + const cipher = 'chacha20'; + + const username = 'username'; + const password = 'password'; + + const obfs_host = 'obfs.com'; + const obfs_path = '/resource/file'; + + const ssr_protocol = 'auth_chain_b'; + const ssr_protocol_param = 'def'; + const ssr_obfs = 'tls1.2_ticket_fastauth'; + const ssr_obfs_param = 'obfs.com'; + + const uuid = '23ad6b10-8d1a-40f7-8ad0-e3e35cd32291'; + + const sni = 'sni.com'; + + const tls_fingerprint = + '67:1B:C8:F2:D4:60:DD:A7:EE:60:DA:BB:A3:F9:A4:D7:C8:29:0F:3E:2F:75:B6:A9:46:88:48:7D:D3:97:7E:98'; + + const SS = { + SIMPLE: { + input: { + Loon: `${name}=shadowsocks,${server},${port},${cipher},"${password}"`, + QX: `shadowsocks=${server}:${port},method=${cipher},password=${password},tag=${name}`, + Surge: `${name}=ss,${server},${port},encrypt-method=${cipher},password=${password}`, + }, + expected: { + type: 'ss', + name, + server, + port, + cipher, + password, + }, + }, + OBFS_TLS: { + input: { + Loon: `${name}=shadowsocks,${server},${port},${cipher},"${password}",obfs-name=tls,obfs-uri=${obfs_path},obfs-host=${obfs_host}`, + QX: `shadowsocks=${server}:${port},method=${cipher},password=${password},obfs=tls,obfs-host=${obfs_host},obfs-uri=${obfs_path},tag=${name}`, + Surge: `${name}=ss,${server},${port},encrypt-method=${cipher},password=${password},obfs=tls,obfs-host=${obfs_host},obfs-uri=${obfs_path}`, + }, + expected: { + type: 'ss', + name, + server, + port, + cipher, + password, + plugin: 'obfs', + 'plugin-opts': { + mode: 'tls', + path: obfs_path, + host: obfs_host, + }, + }, + }, + OBFS_HTTP: { + input: { + Loon: `${name}=shadowsocks,${server},${port},${cipher},"${password}",obfs-name=http,obfs-uri=${obfs_path},obfs-host=${obfs_host}`, + QX: `shadowsocks=${server}:${port},method=${cipher},password=${password},obfs=http,obfs-host=${obfs_host},obfs-uri=${obfs_path},tag=${name}`, + Surge: `${name}=ss,${server},${port},encrypt-method=${cipher},password=${password},obfs=http,obfs-host=${obfs_host},obfs-uri=${obfs_path}`, + }, + expected: { + type: 'ss', + name, + server, + port, + cipher, + password, + plugin: 'obfs', + 'plugin-opts': { + mode: 'http', + path: obfs_path, + host: obfs_host, + }, + }, + }, + V2RAY_PLUGIN_WS: { + input: { + QX: `shadowsocks=${server}:${port},method=${cipher},password=${password},obfs=ws,obfs-host=${obfs_host},obfs-uri=${obfs_path},tag=${name}`, + }, + expected: { + type: 'ss', + name, + server, + port, + cipher, + password, + plugin: 'v2ray-plugin', + 'plugin-opts': { + mode: 'websocket', + path: obfs_path, + host: obfs_host, + }, + }, + }, + V2RAY_PLUGIN_WSS: { + input: { + QX: `shadowsocks=${server}:${port},method=${cipher},password=${password},obfs=wss,obfs-host=${obfs_host},obfs-uri=${obfs_path},tag=${name}`, + }, + expected: { + type: 'ss', + name, + server, + port, + cipher, + password, + plugin: 'v2ray-plugin', + 'plugin-opts': { + mode: 'websocket', + path: obfs_path, + host: obfs_host, + tls: true, + }, + }, + }, + }; + const SSR = { + SIMPLE: { + input: { + QX: `shadowsocks=${server}:${port},method=${cipher},password=${password},ssr-protocol=${ssr_protocol},ssr-protocol-param=${ssr_protocol_param},obfs=${ssr_obfs},obfs-host=${ssr_obfs_param},tag=${name}`, + Loon: `${name}=shadowsocksr,${server},${port},${cipher},"${password}",protocol=${ssr_protocol},protocol-param=${ssr_protocol_param},obfs=${ssr_obfs},obfs-param=${ssr_obfs_param}`, + }, + expected: { + type: 'ssr', + name, + server, + port, + cipher, + password, + obfs: ssr_obfs, + protocol: ssr_protocol, + 'obfs-param': ssr_obfs_param, + 'protocol-param': ssr_protocol_param, + }, + }, + }; + const TROJAN = { + SIMPLE: { + input: { + QX: `trojan=${server}:${port},password=${password},tag=${name}`, + Loon: `${name}=trojan,${server},${port},"${password}"`, + Surge: `${name}=trojan,${server},${port},password=${password}`, + }, + expected: { + type: 'trojan', + name, + server, + port, + password, + }, + }, + WS: { + input: { + QX: `trojan=${server}:${port},password=${password},obfs=ws,obfs-host=${obfs_host},obfs-uri=${obfs_path},tag=${name}`, + Loon: `${name}=trojan,${server},${port},"${password}",transport=ws,path=${obfs_path},host=${obfs_host}`, + Surge: `${name}=trojan,${server},${port},password=${password},ws=true,ws-path=${obfs_path},ws-headers=Host:${obfs_host}`, + }, + expected: { + type: 'trojan', + name, + server, + port, + password, + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + }, + }, + WSS: { + input: { + QX: `trojan=${server}:${port},password=${password},obfs=wss,obfs-host=${obfs_host},obfs-uri=${obfs_path},tls-verification=false,tls-host=${sni},tag=${name}`, + Loon: `${name}=trojan,${server},${port},"${password}",transport=ws,path=${obfs_path},host=${obfs_host},over-tls=true,tls-name=${sni},skip-cert-verify=true`, + Surge: `${name}=trojan,${server},${port},password=${password},ws=true,ws-path=${obfs_path},ws-headers=Host:${obfs_host},skip-cert-verify=true,sni=${sni},tls=true`, + }, + expected: { + type: 'trojan', + name, + server, + port, + password, + network: 'ws', + tls: true, + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + 'skip-cert-verify': true, + sni, + }, + }, + TLS_FINGERPRINT: { + input: { + QX: `trojan=${server}:${port},password=${password},tls-verification=false,tls-host=${sni},tls-cert-sha256=${tls_fingerprint},tag=${name},over-tls=true`, + Surge: `${name}=trojan,${server},${port},password=${password},skip-cert-verify=true,sni=${sni},tls=true,server-cert-fingerprint-sha256=${tls_fingerprint}`, + }, + expected: { + type: 'trojan', + name, + server, + port, + password, + tls: true, + 'skip-cert-verify': true, + sni, + 'tls-fingerprint': tls_fingerprint, + }, + }, + }; + const VMESS = { + SIMPLE: { + input: { + QX: `vmess=${server}:${port},method=${cipher},password=${uuid},tag=${name}`, + Loon: `${name}=vmess,${server},${port},${cipher},"${uuid}"`, + Surge: `${name}=vmess,${server},${port},username=${uuid}`, + }, + expected: { + QX: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + alterId: 0, + }, + Loon: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + alterId: 0, + }, + Surge: { + type: 'vmess', + name, + server, + port, + uuid, + cipher: 'none', // Surge lacks support for specifying cipher for vmess protocol! + alterId: 0, + }, + }, + }, + AEAD: { + input: { + QX: `vmess=${server}:${port},method=${cipher},password=${uuid},aead=true,tag=${name}`, + Loon: `${name}=vmess,${server},${port},${cipher},"${uuid}",alterId=0`, + Surge: `${name}=vmess,${server},${port},username=${uuid},vmess-aead=true`, + }, + expected: { + QX: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + aead: true, + alterId: 0, + }, + Loon: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + alterId: 0, + }, + Surge: { + type: 'vmess', + name, + server, + port, + uuid, + cipher: 'none', // Surge lacks support for specifying cipher for vmess protocol! + alterId: 0, + aead: true, + }, + }, + }, + WS: { + input: { + QX: `vmess=${server}:${port},method=${cipher},password=${uuid},obfs=ws,obfs-host=${obfs_host},obfs-uri=${obfs_path},tag=${name}`, + Loon: `${name}=vmess,${server},${port},${cipher},"${uuid}",transport=ws,host=${obfs_host},path=${obfs_path}`, + Surge: `${name}=vmess,${server},${port},username=${uuid},ws=true,ws-path=${obfs_path},ws-headers=Host:${obfs_host}`, + }, + expected: { + QX: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + alterId: 0, + }, + Loon: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + alterId: 0, + }, + Surge: { + type: 'vmess', + name, + server, + port, + uuid, + cipher: 'none', // Surge lacks support for specifying cipher for vmess protocol! + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + alterId: 0, + }, + }, + }, + WSS: { + input: { + QX: `vmess=${server}:${port},method=${cipher},password=${uuid},obfs=wss,obfs-host=${obfs_host},obfs-uri=${obfs_path},tls-verification=false,tls-host=${sni},tag=${name}`, + Loon: `${name}=vmess,${server},${port},${cipher},"${uuid}",transport=ws,host=${obfs_host},path=${obfs_path},over-tls=true,tls-name=${sni},skip-cert-verify=true`, + Surge: `${name}=vmess,${server},${port},username=${uuid},ws=true,ws-path=${obfs_path},ws-headers=Host:${obfs_host},skip-cert-verify=true,sni=${sni},tls=true`, + }, + expected: { + QX: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + tls: true, + 'skip-cert-verify': true, + sni, + alterId: 0, + }, + Loon: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + tls: true, + 'skip-cert-verify': true, + sni, + alterId: 0, + }, + Surge: { + type: 'vmess', + name, + server, + port, + uuid, + cipher: 'none', // Surge lacks support for specifying cipher for vmess protocol! + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + tls: true, + 'skip-cert-verify': true, + sni, + alterId: 0, + }, + }, + }, + HTTP: { + input: { + QX: `vmess=${server}:${port},method=${cipher},password=${uuid},obfs=http,obfs-host=${obfs_host},obfs-uri=${obfs_path},tag=${name}`, + Loon: `${name}=vmess,${server},${port},${cipher},"${uuid}",transport=http,host=${obfs_host},path=${obfs_path}`, + }, + expected: { + QX: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + network: 'http', + 'http-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + alterId: 0, + }, + Loon: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + network: 'http', + 'http-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + alterId: 0, + }, + }, + }, + HTTP_TLS: { + input: { + Loon: `${name}=vmess,${server},${port},${cipher},"${uuid}",transport=http,host=${obfs_host},path=${obfs_path},over-tls=true,tls-name=${sni},skip-cert-verify=true`, + }, + expected: { + Loon: { + type: 'vmess', + name, + server, + port, + uuid, + cipher, + network: 'http', + 'http-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + tls: true, + 'skip-cert-verify': true, + sni, + alterId: 0, + }, + }, + }, + }; + const VLESS = { + SIMPLE: { + input: { + Loon: `${name}=vless,${server},${port},"${uuid}"`, + }, + expected: { + Loon: { + type: 'vless', + name, + server, + port, + uuid, + }, + }, + }, + WS: { + input: { + Loon: `${name}=vless,${server},${port},"${uuid}",transport=ws,host=${obfs_host},path=${obfs_path}`, + }, + expected: { + Loon: { + type: 'vless', + name, + server, + port, + uuid, + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + }, + }, + }, + WSS: { + input: { + Loon: `${name}=vless,${server},${port},"${uuid}",transport=ws,host=${obfs_host},path=${obfs_path},over-tls=true,tls-name=${sni},skip-cert-verify=true`, + }, + expected: { + Loon: { + type: 'vless', + name, + server, + port, + uuid, + network: 'ws', + 'ws-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + tls: true, + 'skip-cert-verify': true, + sni, + }, + }, + }, + HTTP: { + input: { + Loon: `${name}=vless,${server},${port},"${uuid}",transport=http,host=${obfs_host},path=${obfs_path}`, + }, + expected: { + Loon: { + type: 'vless', + name, + server, + port, + uuid, + network: 'http', + 'http-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + }, + }, + }, + HTTP_TLS: { + input: { + Loon: `${name}=vless,${server},${port},"${uuid}",transport=http,host=${obfs_host},path=${obfs_path},over-tls=true,tls-name=${sni},skip-cert-verify=true`, + }, + expected: { + Loon: { + type: 'vless', + name, + server, + port, + uuid, + network: 'http', + 'http-opts': { + path: obfs_path, + headers: { + Host: obfs_host, + }, + }, + tls: true, + 'skip-cert-verify': true, + sni, + }, + }, + }, + }; + const HTTP = { + SIMPLE: { + input: { + Loon: `${name}=http,${server},${port}`, + QX: `http=${server}:${port},tag=${name}`, + Surge: `${name}=http,${server},${port}`, + }, + expected: { + type: 'http', + name, + server, + port, + }, + }, + AUTH: { + input: { + Loon: `${name}=http,${server},${port},${username},"${password}"`, + QX: `http=${server}:${port},tag=${name},username=${username},password=${password}`, + Surge: `${name}=http,${server},${port},${username},${password}`, + }, + expected: { + type: 'http', + name, + server, + port, + username, + password, + }, + }, + TLS: { + input: { + Loon: `${name}=https,${server},${port},${username},"${password}",tls-name=${sni},skip-cert-verify=true`, + QX: `http=${server}:${port},username=${username},password=${password},over-tls=true,tls-host=${sni},tls-verification=false,tag=${name}`, + Surge: `${name}=https,${server},${port},${username},${password},sni=${sni},skip-cert-verify=true`, + }, + expected: { + type: 'http', + name, + server, + port, + username, + password, + sni, + 'skip-cert-verify': true, + tls: true, + }, + }, + }; + const SOCKS5 = { + SIMPLE: { + input: { + QX: `socks5=${server}:${port},tag=${name}`, + Surge: `${name}=socks5,${server},${port}`, + }, + expected: { + type: 'socks5', + name, + server, + port, + }, + }, + AUTH: { + input: { + QX: `socks5=${server}:${port},tag=${name},username=${username},password=${password}`, + Surge: `${name}=socks5,${server},${port},${username},${password}`, + }, + expected: { + type: 'socks5', + name, + server, + port, + username, + password, + }, + }, + TLS: { + input: { + QX: `socks5=${server}:${port},username=${username},password=${password},over-tls=true,tls-host=${sni},tls-verification=false,tag=${name}`, + Surge: `${name}=socks5-tls,${server},${port},${username},${password},sni=${sni},skip-cert-verify=true`, + }, + expected: { + type: 'socks5', + name, + server, + port, + username, + password, + sni, + 'skip-cert-verify': true, + tls: true, + }, + }, + }; + const SNELL = { + SIMPLE: { + input: { + Surge: `${name}=snell,${server},${port},psk=${password},version=3`, + }, + expected: { + type: 'snell', + name, + server, + port, + psk: password, + version: 3, + }, + }, + OBFS_HTTP: { + input: { + Surge: `${name}=snell,${server},${port},psk=${password},version=3,obfs=http,obfs-host=${obfs_host},obfs-uri=${obfs_path}`, + }, + expected: { + type: 'snell', + name, + server, + port, + psk: password, + version: 3, + 'obfs-opts': { + mode: 'http', + host: obfs_host, + path: obfs_path, + }, + }, + }, + OBFS_TLS: { + input: { + Surge: `${name}=snell,${server},${port},psk=${password},version=3,obfs=tls,obfs-host=${obfs_host},obfs-uri=${obfs_path}`, + }, + expected: { + type: 'snell', + name, + server, + port, + psk: password, + version: 3, + 'obfs-opts': { + mode: 'tls', + host: obfs_host, + path: obfs_path, + }, + }, + }, + }; + return { + SS, + SSR, + VMESS, + VLESS, + TROJAN, + HTTP, + SOCKS5, + SNELL, + }; +} + +export default createTestCases(); diff --git a/backend/src/utils/database.js b/backend/src/utils/database.js new file mode 100644 index 0000000000..9786046b19 --- /dev/null +++ b/backend/src/utils/database.js @@ -0,0 +1,17 @@ +export function findByName(list, name, field = 'name') { + return list.find((item) => item[field] === name); +} + +export function findIndexByName(list, name, field = 'name') { + return list.findIndex((item) => item[field] === name); +} + +export function deleteByName(list, name, field = 'name') { + const idx = findIndexByName(list, name, field); + list.splice(idx, 1); +} + +export function updateByName(list, name, newItem, field = 'name') { + const idx = findIndexByName(list, name, field); + list[idx] = newItem; +} diff --git a/backend/src/utils/dns.js b/backend/src/utils/dns.js new file mode 100644 index 0000000000..0c7366d5ab --- /dev/null +++ b/backend/src/utils/dns.js @@ -0,0 +1,50 @@ +import $ from '@/core/app'; +import dnsPacket from 'dns-packet'; +import { Buffer } from 'buffer'; +import { isIPv4 } from '@/utils'; + +export async function doh({ url, domain, type = 'A', timeout, edns }) { + const buf = dnsPacket.encode({ + type: 'query', + id: 0, + flags: dnsPacket.RECURSION_DESIRED, + questions: [ + { + type, + name: domain, + }, + ], + additionals: [ + { + type: 'OPT', + name: '.', + udpPayloadSize: 4096, + flags: 0, + options: [ + { + code: 'CLIENT_SUBNET', + ip: edns, + sourcePrefixLength: isIPv4(edns) ? 24 : 56, + scopePrefixLength: 0, + }, + ], + }, + ], + }); + const res = await $.http.get({ + url: `${url}?dns=${buf + .toString('base64') + .toString('utf-8') + .replace(/=/g, '')}`, + headers: { + Accept: 'application/dns-message', + // 'Content-Type': 'application/dns-message', + }, + // body: buf, + 'binary-mode': true, + encoding: null, // 使用 null 编码以确保响应是原始二进制数据 + timeout, + }); + + return dnsPacket.decode(Buffer.from($.env.isQX ? res.bodyBytes : res.body)); +} diff --git a/backend/src/utils/download.js b/backend/src/utils/download.js new file mode 100644 index 0000000000..d886edff70 --- /dev/null +++ b/backend/src/utils/download.js @@ -0,0 +1,297 @@ +import { SETTINGS_KEY } from '@/constants'; +import { HTTP, ENV } from '@/vendor/open-api'; +import { hex_md5 } from '@/vendor/md5'; +import { getPolicyDescriptor } from '@/utils'; +import resourceCache from '@/utils/resource-cache'; +import headersResourceCache from '@/utils/headers-resource-cache'; +import { + getFlowField, + getFlowHeaders, + parseFlowHeaders, + validCheck, +} from '@/utils/flow'; +import $ from '@/core/app'; +import PROXY_PREPROCESSORS from '@/core/proxy-utils/preprocessors'; +const clashPreprocessor = PROXY_PREPROCESSORS.find( + (processor) => processor.name === 'Clash Pre-processor', +); + +const tasks = new Map(); + +export default async function download( + rawUrl = '', + ua, + timeout, + customProxy, + skipCustomCache, + awaitCustomCache, + noCache, + preprocess, +) { + let $arguments = {}; + let url = rawUrl.replace(/#noFlow$/, ''); + const rawArgs = url.split('#'); + url = url.split('#')[0]; + if (rawArgs.length > 1) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $arguments = JSON.parse(decodeURIComponent(rawArgs[1])); + } catch (e) { + for (const pair of rawArgs[1].split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $arguments[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + } + const { isNode, isStash, isLoon, isShadowRocket, isQX } = ENV(); + const { + defaultProxy, + defaultUserAgent, + defaultTimeout, + cacheThreshold: defaultCacheThreshold, + } = $.read(SETTINGS_KEY); + const cacheThreshold = defaultCacheThreshold || 1024; + let proxy = customProxy || defaultProxy; + if ($.env.isNode) { + proxy = proxy || eval('process.env.SUB_STORE_BACKEND_DEFAULT_PROXY'); + } + const userAgent = ua || defaultUserAgent || 'clash.meta'; + const requestTimeout = timeout || defaultTimeout || 8000; + const id = hex_md5(userAgent + url); + + if ($arguments?.cacheKey === true) { + $.error(`使用自定义缓存时 cacheKey 的值不能为空`); + $arguments.cacheKey = undefined; + } + + const customCacheKey = $arguments?.cacheKey + ? `#sub-store-cached-custom-${$arguments?.cacheKey}` + : undefined; + + if (customCacheKey && !skipCustomCache) { + const customCached = $.read(customCacheKey); + const cached = resourceCache.get(id); + if (!noCache && !$arguments?.noCache && cached) { + $.info( + `乐观缓存: URL ${url}\n存在有效的常规缓存\n使用常规缓存以避免重复请求`, + ); + return cached; + } + if (customCached) { + if (awaitCustomCache) { + $.info(`乐观缓存: URL ${url}\n本次进行请求 尝试更新缓存`); + try { + await download( + rawUrl.replace(/(\?|&)cacheKey=.*?(&|$)/, ''), + ua, + timeout, + proxy, + true, + undefined, + undefined, + preprocess, + ); + } catch (e) { + $.error( + `乐观缓存: URL ${url} 更新缓存发生错误 ${ + e.message ?? e + }`, + ); + $.info('使用乐观缓存的数据刷新缓存, 防止后续请求'); + resourceCache.set(id, customCached); + } + } else { + $.info( + `乐观缓存: URL ${url}\n本次返回自定义缓存 ${$arguments?.cacheKey}\n并进行请求 尝试异步更新缓存`, + ); + download( + rawUrl.replace(/(\?|&)cacheKey=.*?(&|$)/, ''), + ua, + timeout, + proxy, + true, + undefined, + undefined, + preprocess, + ).catch((e) => { + $.error( + `乐观缓存: URL ${url} 异步更新缓存发生错误 ${ + e.message ?? e + }`, + ); + }); + } + return customCached; + } + } + + // const downloadUrlMatch = url.match(/^\/api\/(file|module)\/(.+)/); + // if (downloadUrlMatch) { + // let type = downloadUrlMatch?.[1]; + // let name = downloadUrlMatch?.[2]; + // if (name == null) { + // throw new Error(`本地 ${type} URL 无效: ${url}`); + // } + // name = decodeURIComponent(name); + // const key = type === 'module' ? MODULES_KEY : FILES_KEY; + // const item = findByName($.read(key), name); + // if (!item) { + // throw new Error(`找不到本地 ${type}: ${name}`); + // } + + // return item.content; + // } + + if (!isNode && tasks.has(id)) { + return tasks.get(id); + } + + const http = HTTP({ + headers: { + 'User-Agent': userAgent, + ...(isStash && proxy + ? { 'X-Stash-Selected-Proxy': encodeURIComponent(proxy) } + : {}), + ...(isShadowRocket && proxy ? { 'X-Surge-Policy': proxy } : {}), + }, + timeout: requestTimeout, + }); + + let result; + + // try to find in app cache + const cached = resourceCache.get(id); + if (!noCache && !$arguments?.noCache && cached) { + $.info(`使用缓存: ${url}, ${userAgent}`); + result = cached; + if (customCacheKey) { + $.info(`URL ${url}\n写入自定义缓存 ${$arguments?.cacheKey}`); + $.write(cached, customCacheKey); + } + } else { + const insecure = $arguments?.insecure + ? isNode + ? { strictSSL: false } + : { insecure: true } + : undefined; + $.info( + `Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nProxy: ${proxy}\nInsecure: ${!!insecure}\nPreprocess: ${preprocess}\nURL: ${url}`, + ); + try { + let { body, headers, statusCode } = await http.get({ + url, + ...(proxy ? { proxy } : {}), + ...(isLoon && proxy ? { node: proxy } : {}), + ...(isQX && proxy ? { opts: { policy: proxy } } : {}), + ...(proxy ? getPolicyDescriptor(proxy) : {}), + ...(insecure ? insecure : {}), + }); + $.info(`statusCode: ${statusCode}`); + if (statusCode < 200 || statusCode >= 400) { + throw new Error(`statusCode: ${statusCode}`); + } + + if (headers) { + const flowInfo = getFlowField(headers); + if (flowInfo) { + headersResourceCache.set(id, flowInfo); + } + } + if (body.replace(/\s/g, '').length === 0) + throw new Error(new Error('远程资源内容为空')); + if (preprocess) { + try { + if (clashPreprocessor.test(body)) { + body = clashPreprocessor.parse(body, true); + } + } catch (e) { + $.error(`Clash Pre-processor error: ${e}`); + } + } + let shouldCache = true; + if (cacheThreshold) { + const size = body.length / 1024; + if (size > cacheThreshold) { + $.info( + `资源大小 ${size.toFixed( + 2, + )} KB 超过了 ${cacheThreshold} KB, 不缓存`, + ); + shouldCache = false; + } + } + if (shouldCache) { + resourceCache.set(id, body); + if (customCacheKey) { + $.info( + `URL ${url}\n写入自定义缓存 ${$arguments?.cacheKey}`, + ); + $.write(body, customCacheKey); + } + } + + result = body; + } catch (e) { + if (customCacheKey) { + const cached = $.read(customCacheKey); + if (cached) { + $.info( + `无法下载 URL ${url}: ${ + e.message ?? e + }\n使用自定义缓存 ${$arguments?.cacheKey}`, + ); + return cached; + } + } + throw new Error(`无法下载 URL ${url}: ${e.message ?? e}`); + } + } + + // 检查订阅有效性 + + if ($arguments?.validCheck) { + await validCheck( + parseFlowHeaders( + await getFlowHeaders( + url, + $arguments.flowUserAgent, + undefined, + proxy, + $arguments.flowUrl, + ), + ), + ); + } + + if (!isNode) { + tasks.set(id, result); + } + return result; +} + +export async function downloadFile(url, file) { + const undici = eval("require('undici')"); + const fs = eval("require('fs')"); + const { pipeline } = eval("require('stream/promises')"); + const { Agent, interceptors, request } = undici; + $.info(`Downloading file...\nURL: ${url}\nFile: ${file}`); + const { body, statusCode } = await request(url, { + dispatcher: new Agent().compose( + interceptors.redirect({ + maxRedirections: 3, + throwOnRedirect: true, + }), + ), + }); + if (statusCode !== 200) + throw new Error(`Failed to download file from ${url}`); + const fileStream = fs.createWriteStream(file); + await pipeline(body, fileStream); + $.info(`File downloaded from ${url} to ${file}`); + return file; +} diff --git a/backend/src/utils/env.js b/backend/src/utils/env.js new file mode 100644 index 0000000000..d7249bd69c --- /dev/null +++ b/backend/src/utils/env.js @@ -0,0 +1,69 @@ +import { version as substoreVersion } from '../../package.json'; +import { ENV } from '@/vendor/open-api'; + +const { + isNode, + isQX, + isLoon, + isSurge, + isStash, + isShadowRocket, + isLanceX, + isEgern, + isGUIforCores, +} = ENV(); +let backend = 'Node'; +if (isNode) backend = 'Node'; +if (isQX) backend = 'QX'; +if (isLoon) backend = 'Loon'; +if (isSurge) backend = 'Surge'; +if (isStash) backend = 'Stash'; +if (isShadowRocket) backend = 'ShadowRocket'; +if (isEgern) backend = 'Egern'; +if (isLanceX) backend = 'LanceX'; +if (isGUIforCores) backend = 'GUI.for.Cores'; + +let meta = {}; +let feature = {}; + +try { + if (typeof $environment !== 'undefined') { + // eslint-disable-next-line no-undef + meta.env = $environment; + } + if (typeof $loon !== 'undefined') { + // eslint-disable-next-line no-undef + meta.loon = $loon; + } + if (typeof $script !== 'undefined') { + // eslint-disable-next-line no-undef + meta.script = $script; + } + if (typeof $Plugin !== 'undefined') { + // eslint-disable-next-line no-undef + meta.plugin = $Plugin; + } + if (isNode) { + meta.node = { + version: eval('process.version'), + argv: eval('process.argv'), + filename: eval('__filename'), + dirname: eval('__dirname'), + env: {}, + }; + const env = eval('process.env'); + for (const key in env) { + if (/^SUB_STORE_/.test(key)) { + meta.node.env[key] = env[key]; + } + } + } + // eslint-disable-next-line no-empty +} catch (e) {} + +export default { + backend, + version: substoreVersion, + feature, + meta, +}; diff --git a/backend/src/utils/flow.js b/backend/src/utils/flow.js new file mode 100644 index 0000000000..b45e48edeb --- /dev/null +++ b/backend/src/utils/flow.js @@ -0,0 +1,353 @@ +import { SETTINGS_KEY } from '@/constants'; +import { HTTP, ENV } from '@/vendor/open-api'; +import { hex_md5 } from '@/vendor/md5'; +import { getPolicyDescriptor } from '@/utils'; +import $ from '@/core/app'; +import headersResourceCache from '@/utils/headers-resource-cache'; + +export function getFlowField(headers) { + const keys = Object.keys(headers); + let sub = ''; + let webPage = ''; + for (let k of keys) { + const lower = k.toLowerCase(); + if (lower === 'subscription-userinfo') { + sub = headers[k]; + } else if (lower === 'profile-web-page-url') { + webPage = headers[k]; + } + } + + return `${sub || ''}${ + webPage ? `; app_url=${encodeURIComponent(webPage)}` : '' + }`; +} +export async function getFlowHeaders( + rawUrl, + ua, + timeout, + customProxy, + flowUrl, +) { + let url = flowUrl || rawUrl || ''; + let $arguments = {}; + const rawArgs = url.split('#'); + url = url.split('#')[0]; + if (rawArgs.length > 1) { + try { + // 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}` + $arguments = JSON.parse(decodeURIComponent(rawArgs[1])); + } catch (e) { + for (const pair of rawArgs[1].split('&')) { + const key = pair.split('=')[0]; + const value = pair.split('=')[1]; + // 部分兼容之前的逻辑 const value = pair.split('=')[1] || true; + $arguments[key] = + value == null || value === '' + ? true + : decodeURIComponent(value); + } + } + } + if ($arguments?.noFlow) { + return; + } + const { isStash, isLoon, isShadowRocket, isQX } = ENV(); + const insecure = $arguments?.insecure + ? $.env.isNode + ? { strictSSL: false } + : { insecure: true } + : undefined; + const { defaultProxy, defaultFlowUserAgent, defaultTimeout } = + $.read(SETTINGS_KEY); + let proxy = customProxy || defaultProxy; + if ($.env.isNode) { + proxy = proxy || eval('process.env.SUB_STORE_BACKEND_DEFAULT_PROXY'); + } + const userAgent = ua || defaultFlowUserAgent || 'clash'; + const requestTimeout = timeout || defaultTimeout || 8000; + const id = hex_md5(userAgent + url); + const cached = headersResourceCache.get(id); + let flowInfo; + if (!$arguments?.noCache && cached) { + $.info(`使用缓存的流量信息: ${url}, ${userAgent}`); + flowInfo = cached; + } else { + const http = HTTP(); + if (flowUrl) { + $.info( + `使用 GET 方法从响应体获取流量信息: ${flowUrl}, User-Agent: ${ + userAgent || '' + }, Insecure: ${!!insecure}, Proxy: ${proxy}`, + ); + const { body } = await http.get({ + url: flowUrl, + headers: { + 'User-Agent': userAgent, + }, + timeout: requestTimeout, + ...(proxy ? { proxy } : {}), + ...(isLoon && proxy ? { node: proxy } : {}), + ...(isQX && proxy ? { opts: { policy: proxy } } : {}), + ...(proxy ? getPolicyDescriptor(proxy) : {}), + ...(insecure ? insecure : {}), + }); + flowInfo = body; + } else { + try { + $.info( + `使用 HEAD 方法从响应头获取流量信息: ${url}, User-Agent: ${ + userAgent || '' + }, Insecure: ${!!insecure}, Proxy: ${proxy}`, + ); + const { headers } = await http.head({ + url: url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length)[0], + headers: { + 'User-Agent': userAgent, + ...(isStash && proxy + ? { + 'X-Stash-Selected-Proxy': + encodeURIComponent(proxy), + } + : {}), + ...(isShadowRocket && proxy + ? { 'X-Surge-Policy': proxy } + : {}), + }, + timeout: requestTimeout, + ...(proxy ? { proxy } : {}), + ...(isLoon && proxy ? { node: proxy } : {}), + ...(isQX && proxy ? { opts: { policy: proxy } } : {}), + ...(proxy ? getPolicyDescriptor(proxy) : {}), + ...(insecure ? insecure : {}), + }); + flowInfo = getFlowField(headers); + } catch (e) { + $.error( + `使用 HEAD 方法从响应头获取流量信息失败: ${url}, User-Agent: ${ + userAgent || '' + }, Insecure: ${!!insecure}, Proxy: ${proxy}: ${ + e.message ?? e + }`, + ); + } + if (!flowInfo) { + $.info( + `使用 GET 方法获取流量信息: ${url}, User-Agent: ${ + userAgent || '' + }, Insecure: ${!!insecure}, Proxy: ${proxy}`, + ); + const { headers } = await http.get({ + url: url + .split(/[\r\n]+/) + .map((i) => i.trim()) + .filter((i) => i.length)[0], + headers: { + 'User-Agent': userAgent, + ...(isStash && proxy + ? { + 'X-Stash-Selected-Proxy': + encodeURIComponent(proxy), + } + : {}), + ...(isShadowRocket && proxy + ? { 'X-Surge-Policy': proxy } + : {}), + }, + timeout: requestTimeout, + ...(proxy ? { proxy } : {}), + ...(isLoon && proxy ? { node: proxy } : {}), + ...(isQX && proxy ? { opts: { policy: proxy } } : {}), + ...(proxy ? getPolicyDescriptor(proxy) : {}), + ...(insecure ? insecure : {}), + }); + flowInfo = getFlowField(headers); + } + } + if (flowInfo) { + flowInfo = flowInfo.trim(); + } + if (flowInfo) { + headersResourceCache.set(id, flowInfo); + } + } + + return flowInfo; +} +export function parseFlowHeaders(flowHeaders) { + if (!flowHeaders) return; + // unit is KB + const uploadMatch = flowHeaders.match( + /upload=([-+]?)([0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)/, + ); + const upload = Number(uploadMatch[1] + uploadMatch[2]); + + const downloadMatch = flowHeaders.match( + /download=([-+]?)([0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)/, + ); + const download = Number(downloadMatch[1] + downloadMatch[2]); + const totalMatch = flowHeaders.match( + /total=([-+]?)([0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)/, + ); + const total = Number(totalMatch[1] + totalMatch[2]); + + // optional expire timestamp + const expireMatch = flowHeaders.match( + /expire=([-+]?)([0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)/, + ); + const expires = expireMatch + ? Number(expireMatch[1] + expireMatch[2]) + : undefined; + + const remainingDaysMatch = flowHeaders.match(/reset_day=([0-9]+)/); + const remainingDays = remainingDaysMatch + ? Number(remainingDaysMatch[1]) + : undefined; + + const appUrlMatch = flowHeaders.match(/app_url=(.*?)\s*?(;|$)/); + const appUrl = appUrlMatch ? decodeURIComponent(appUrlMatch[1]) : undefined; + + const planNameMatch = flowHeaders.match(/plan_name=(.*?)\s*?(;|$)/); + const planName = planNameMatch + ? decodeURIComponent(planNameMatch[1]) + : undefined; + + return { + expires, + total, + usage: { upload, download }, + remainingDays, + appUrl, + planName, + }; +} + +export function flowTransfer(flow, unit = 'B') { + const unitList = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + let unitIndex = unitList.indexOf(unit); + + return flow < 1024 || unitIndex === unitList.length - 1 + ? { value: flow.toFixed(1), unit: unit } + : flowTransfer(flow / 1024, unitList[++unitIndex]); +} + +export function validCheck(flow) { + if (!flow) { + throw new Error('没有流量信息'); + } + if (flow?.expires && flow.expires * 1000 < Date.now()) { + const date = new Date(flow.expires * 1000).toLocaleDateString(); + throw new Error(`订阅已过期: ${date}`); + } + if (flow?.total) { + const upload = flow.usage?.upload || 0; + const download = flow.usage?.download || 0; + if (flow.total - upload - download < 0) { + const current = upload + download; + const currT = flowTransfer(Math.abs(current)); + currT.value = current < 0 ? '-' + currT.value : currT.value; + const totalT = flowTransfer(flow.total); + throw new Error( + `流量已用完: ${currT.value} ${currT.unit} / ${totalT.value} ${totalT.unit}`, + ); + } + } +} + +export function getRmainingDays(opt = {}) { + try { + let { resetDay, startDate, cycleDays } = opt; + if (['string', 'number'].includes(typeof opt)) { + resetDay = opt; + } + + if (startDate && cycleDays) { + cycleDays = parseInt(cycleDays); + if (isNaN(cycleDays) || cycleDays <= 0) + throw new Error('重置周期应为正整数'); + if (!startDate || !Date.parse(startDate)) + throw new Error('开始日期不合法'); + + const start = new Date(startDate); + const today = new Date(); + start.setHours(0, 0, 0, 0); + today.setHours(0, 0, 0, 0); + if (start.getTime() > today.getTime()) + throw new Error('开始日期应早于现在'); + + let resetDate = new Date(startDate); + resetDate.setDate(resetDate.getDate() + cycleDays); + + while (resetDate < today) { + resetDate.setDate(resetDate.getDate() + cycleDays); + } + + resetDate.setHours(0, 0, 0, 0); + const timeDiff = resetDate.getTime() - today.getTime(); + const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24)); + + return daysDiff; + } else { + if (!resetDay) return; + resetDay = parseInt(resetDay); + if (isNaN(resetDay) || resetDay <= 0 || resetDay > 31) + throw new Error('月重置日应为 1-31 之间的整数'); + let now = new Date(); + let today = now.getDate(); + let month = now.getMonth(); + let year = now.getFullYear(); + let daysInMonth; + + if (resetDay > today) { + daysInMonth = 0; + } else { + daysInMonth = new Date(year, month + 1, 0).getDate(); + } + + return daysInMonth - today + resetDay; + } + } catch (e) { + $.error(`getRmainingDays failed: ${e.message ?? e}`); + } +} + +export function normalizeFlowHeader(flowHeaders) { + try { + // 使用 Map 保持顺序并处理重复键 + const kvMap = new Map(); + + flowHeaders + .split(';') + .map((p) => p.trim()) + .filter(Boolean) + .forEach((pair) => { + const eqIndex = pair.indexOf('='); + if (eqIndex === -1) return; + + const key = pair.slice(0, eqIndex).trim(); + const encodedValue = pair.slice(eqIndex + 1).trim(); + + // 只保留第一个出现的 key + if (!kvMap.has(key)) { + try { + // 解码 URI 组件并保留原始值作为 fallback + const decodedValue = decodeURIComponent(encodedValue); + kvMap.set(key, decodedValue); + } catch (e) { + kvMap.set(key, encodedValue); + } + } + }); + + // 拼接标准化字符串 + return Array.from(kvMap.entries()) + .map(([k, v]) => `${k}=${encodeURIComponent(v)}`) // 重新编码保持兼容性 + .join('; '); + } catch (e) { + $.error(`normalizeFlowHeader failed: ${e.message ?? e}`); + return flowHeaders; + } +} diff --git a/backend/src/utils/geo.js b/backend/src/utils/geo.js new file mode 100644 index 0000000000..870d43f5ff --- /dev/null +++ b/backend/src/utils/geo.js @@ -0,0 +1,518 @@ +import $ from '@/core/app'; + +const ISOFlags = { + '🏳️‍🌈': ['EXP', 'BAND'], + '🇸🇱': ['TEST', 'SOS'], + '🇦🇩': ['AD', 'AND'], + '🇦🇪': ['AE', 'ARE'], + '🇦🇫': ['AF', 'AFG'], + '🇦🇱': ['AL', 'ALB'], + '🇦🇲': ['AM', 'ARM'], + '🇦🇷': ['AR', 'ARG'], + '🇦🇹': ['AT', 'AUT'], + '🇦🇺': ['AU', 'AUS'], + '🇦🇿': ['AZ', 'AZE'], + '🇧🇦': ['BA', 'BIH'], + '🇧🇩': ['BD', 'BGD'], + '🇧🇪': ['BE', 'BEL'], + '🇧🇬': ['BG', 'BGR'], + '🇧🇭': ['BH', 'BHR'], + '🇧🇴': ['BO', 'BOL'], + '🇧🇳': ['BN', 'BRN'], + '🇧🇷': ['BR', 'BRA'], + '🇧🇹': ['BT', 'BTN'], + '🇧🇾': ['BY', 'BLR'], + '🇨🇦': ['CA', 'CAN'], + '🇨🇭': ['CH', 'CHE'], + '🇨🇱': ['CL', 'CHL'], + '🇨🇴': ['CO', 'COL'], + '🇨🇷': ['CR', 'CRI'], + '🇨🇾': ['CY', 'CYP'], + '🇨🇿': ['CZ', 'CZE'], + '🇩🇪': ['DE', 'DEU'], + '🇩🇰': ['DK', 'DNK'], + '🇪🇨': ['EC', 'ECU'], + '🇪🇪': ['EE', 'EST'], + '🇪🇬': ['EG', 'EGY'], + '🇪🇸': ['ES', 'ESP'], + '🇪🇺': ['EU'], + '🇫🇮': ['FI', 'FIN'], + '🇫🇷': ['FR', 'FRA'], + '🇬🇧': ['GB', 'GBR', 'UK'], + '🇬🇪': ['GE', 'GEO'], + '🇬🇷': ['GR', 'GRC'], + '🇬🇹': ['GT', 'GTM'], + '🇬🇺': ['GU', 'GUM'], + '🇭🇰': ['HK', 'HKG', 'HKT', 'HKBN', 'HGC', 'WTT', 'CMI'], + '🇭🇷': ['HR', 'HRV'], + '🇭🇺': ['HU', 'HUN'], + '🇯🇴': ['JO', 'JOR'], + '🇯🇵': ['JP', 'JPN', 'TYO'], + '🇰🇪': ['KE', 'KEN'], + '🇰🇬': ['KG', 'KGZ'], + '🇰🇭': ['KH', 'KGZ'], + '🇰🇵': ['KP', 'PRK'], + '🇰🇷': ['KR', 'KOR', 'SEL'], + '🇰🇿': ['KZ', 'KAZ'], + '🇮🇩': ['ID', 'IDN'], + '🇮🇪': ['IE', 'IRL'], + '🇮🇱': ['IL', 'ISR'], + '🇮🇲': ['IM', 'IMN'], + '🇮🇳': ['IN', 'IND'], + '🇮🇷': ['IR', 'IRN'], + '🇮🇸': ['IS', 'ISL'], + '🇮🇹': ['IT', 'ITA'], + '🇱🇦': ['LA', 'LAO'], + '🇱🇰': ['LK', 'LKA'], + '🇱🇹': ['LT', 'LTU'], + '🇱🇺': ['LU', 'LUX'], + '🇱🇻': ['LV', 'LVA'], + '🇲🇦': ['MA', 'MAR'], + '🇲🇩': ['MD', 'MDA'], + '🇳🇬': ['NG', 'NGA'], + '🇲🇲': ['MM', 'MMR'], + '🇲🇰': ['MK', 'MKD'], + '🇲🇳': ['MN', 'MNG'], + '🇲🇴': ['MO', 'MAC', 'CTM'], + '🇲🇹': ['MT', 'MLT'], + '🇲🇽': ['MX', 'MEX'], + '🇲🇾': ['MY', 'MYS'], + '🇳🇱': ['NL', 'NLD', 'AMS'], + '🇳🇴': ['NO', 'NOR'], + '🇳🇵': ['NP', 'NPL'], + '🇳🇿': ['NZ', 'NZL'], + '🇵🇦': ['PA', 'PAN'], + '🇵🇪': ['PE', 'PER'], + '🇵🇭': ['PH', 'PHL'], + '🇵🇰': ['PK', 'PAK'], + '🇵🇱': ['PL', 'POL'], + '🇵🇷': ['PR', 'PRI'], + '🇵🇹': ['PT', 'PRT'], + '🇵🇾': ['PY', 'PRY'], + '🇵🇬': ['PG', 'PNG'], + '🇷🇴': ['RO', 'ROU'], + '🇷🇸': ['RS', 'SRB'], + '🇷🇪': ['RE', 'REU'], + '🇷🇺': ['RU', 'RUS'], + '🇸🇦': ['SA', 'SAU'], + '🇸🇪': ['SE', 'SWE'], + '🇸🇬': ['SG', 'SGP'], + '🇸🇮': ['SI', 'SVN'], + '🇸🇰': ['SK', 'SVK'], + '🇹🇭': ['TH', 'THA'], + '🇹🇳': ['TN', 'TUN'], + '🇹🇷': ['TR', 'TUR'], + '🇹🇼': ['TW', 'TWN', 'CHT', 'HINET', 'ROC'], + '🇺🇦': ['UA', 'UKR'], + '🇺🇸': ['US', 'USA', 'LAX', 'SFO', 'SJC'], + '🇺🇾': ['UY', 'URY'], + '🇻🇪': ['VE', 'VEN'], + '🇻🇳': ['VN', 'VNM'], + '🇿🇦': ['ZA', 'ZAF', 'JNB'], + '🇨🇳': ['CN', 'CHN', 'BACK'], +}; +// get proxy flag according to its name +export function getFlag(name) { + // flags from @KOP-XIAO: https://github.com/KOP-XIAO/QuantumultX/blob/master/Scripts/resource-parser.js + // flags from @surgioproject: https://github.com/surgioproject/surgio/blob/master/lib/misc/flag_cn.ts + + // refer: https://zh.wikipedia.org/wiki/ISO_3166-1二位字母代码 + // refer: https://zh.wikipedia.org/wiki/ISO_3166-1三位字母代码 + const Flags = { + '🏳️‍🌈': ['流量', '时间', '过期', 'Bandwidth', 'Expire'], + '🇸🇱': ['应急', '测试节点'], + '🇦🇩': ['Andorra', '安道尔'], + '🇦🇪': ['United Arab Emirates', '阿联酋', '迪拜'], + '🇦🇫': ['Afghanistan', '阿富汗'], + '🇦🇱': ['Albania', '阿尔巴尼亚', '阿爾巴尼亞'], + '🇦🇲': ['Armenia', '亚美尼亚'], + '🇦🇷': ['Argentina', '阿根廷'], + '🇦🇹': ['Austria', '奥地利', '奧地利', '维也纳'], + '🇦🇺': [ + 'Australia', + '澳大利亚', + '澳洲', + '墨尔本', + '悉尼', + '土澳', + '京澳', + '廣澳', + '滬澳', + '沪澳', + '广澳', + 'Sydney', + ], + '🇦🇿': ['Azerbaijan', '阿塞拜疆'], + '🇧🇦': ['Bosnia and Herzegovina', '波黑共和国', '波黑'], + '🇧🇩': ['Bangladesh', '孟加拉国', '孟加拉'], + '🇧🇪': ['Belgium', '比利时', '比利時'], + '🇧🇬': ['Bulgaria', '保加利亚', '保加利亞'], + '🇧🇭': ['Bahrain', '巴林'], + '🇧🇷': ['Brazil', '巴西', '圣保罗'], + '🇧🇳': ['Brunei', '文莱', '汶萊'], + '🇧🇾': ['Belarus', '白俄罗斯', '白俄'], + '🇧🇴': ['Bolivia', '玻利维亚'], + '🇧🇹': ['Bhutan', '不丹', '不丹王国'], + '🇨🇦': [ + 'Canada', + '加拿大', + '蒙特利尔', + '温哥华', + '楓葉', + '枫叶', + '滑铁卢', + '多伦多', + 'Waterloo', + 'Toronto', + ], + '🇨🇭': ['Switzerland', '瑞士', '苏黎世', 'Zurich'], + '🇨🇱': ['Chile', '智利'], + '🇨🇴': ['Colombia', '哥伦比亚'], + '🇨🇷': ['Costa Rica', '哥斯达黎加'], + '🇨🇾': ['Cyprus', '塞浦路斯'], + '🇨🇿': ['Czechia', '捷克'], + '🇩🇪': [ + 'German', + '德国', + '德國', + '京德', + '滬德', + '廣德', + '沪德', + '广德', + '法兰克福', + 'Frankfurt', + '德意志', + ], + '🇩🇰': ['Denmark', '丹麦', '丹麥'], + '🇪🇨': ['Ecuador', '厄瓜多尔'], + '🇪🇪': ['Estonia', '爱沙尼亚'], + '🇪🇬': ['Egypt', '埃及'], + '🇪🇸': ['Spain', '西班牙'], + '🇪🇺': ['European Union', '欧盟', '欧罗巴'], + '🇫🇮': ['Finland', '芬兰', '芬蘭', '赫尔辛基'], + '🇫🇷': ['France', '法国', '法國', '巴黎'], + '🇬🇧': [ + 'Great Britain', + '英国', + 'England', + 'United Kingdom', + '伦敦', + '英', + 'London', + ], + '🇬🇪': ['Georgia', '格鲁吉亚', '格魯吉亞'], + '🇬🇷': ['Greece', '希腊', '希臘'], + '🇬🇺': ['Guam', '关岛', '關島'], + '🇬🇹': ['Guatemala', '危地马拉'], + '🇭🇰': [ + 'Hongkong', + '香港', + 'Hong Kong', + 'HongKong', + 'HONG KONG', + '深港', + '沪港', + '呼港', + '穗港', + '京港', + '港', + ], + '🇭🇷': ['Croatia', '克罗地亚', '克羅地亞'], + '🇭🇺': ['Hungary', '匈牙利'], + '🇯🇴': ['Jordan', '约旦'], + '🇯🇵': [ + 'Japan', + '日本', + '东京', + '大阪', + '埼玉', + '沪日', + '穗日', + '川日', + '中日', + '泉日', + '杭日', + '深日', + '辽日', + '广日', + '大坂', + 'Osaka', + 'Tokyo', + ], + '🇰🇪': ['Kenya', '肯尼亚'], + '🇰🇬': ['Kyrgyzstan', '吉尔吉斯斯坦'], + '🇰🇭': ['Cambodia', '柬埔寨'], + '🇰🇵': ['North Korea', '朝鲜'], + '🇰🇷': [ + 'Korea', + '韩国', + '韓國', + '韩', + '韓', + '首尔', + '春川', + 'Chuncheon', + 'Seoul', + ], + '🇰🇿': ['Kazakhstan', '哈萨克斯坦', '哈萨克'], + '🇮🇩': ['Indonesia', '印尼', '印度尼西亚', '雅加达'], + '🇮🇪': ['Ireland', '爱尔兰', '愛爾蘭', '都柏林'], + '🇮🇱': ['Israel', '以色列'], + '🇮🇲': ['Isle of Man', '马恩岛', '馬恩島'], + '🇮🇳': ['India', '印度', '孟买', 'MFumbai', 'Mumbai'], + '🇮🇷': ['Iran', '伊朗'], + '🇮🇸': ['Iceland', '冰岛', '冰島'], + '🇮🇹': ['Italy', '意大利', '義大利', '米兰', 'Nachash'], + '🇱🇰': ['Sri Lanka', '斯里兰卡', '斯里蘭卡'], + '🇱🇦': ['Laos', '老挝', '老撾'], + '🇱🇹': ['Lithuania', '立陶宛'], + '🇱🇺': ['Luxembourg', '卢森堡'], + '🇱🇻': ['Latvia', '拉脱维亚', 'Latvija'], + '🇲🇦': ['Morocco', '摩洛哥'], + '🇲🇩': ['Moldova', '摩尔多瓦', '摩爾多瓦'], + '🇲🇲': ['Myanmar', '缅甸', '緬甸'], + '🇳🇬': ['Nigeria', '尼日利亚', '尼日利亞'], + '🇲🇰': ['Macedonia', '马其顿', '馬其頓'], + '🇲🇳': ['Mongolia', '蒙古'], + '🇲🇴': ['Macao', '澳门', '澳門', 'CTM'], + '🇲🇹': ['Malta', '马耳他'], + '🇲🇽': ['Mexico', '墨西哥'], + '🇲🇾': ['Malaysia', '马来', '馬來', '吉隆坡', '大馬'], + '🇳🇱': [ + 'Netherlands', + '荷兰', + '荷蘭', + '尼德蘭', + '阿姆斯特丹', + 'Amsterdam', + ], + '🇳🇴': ['Norway', '挪威'], + '🇳🇵': ['Nepal', '尼泊尔'], + '🇳🇿': ['New Zealand', '新西兰', '新西蘭'], + '🇵🇦': ['Panama', '巴拿马'], + '🇵🇪': ['Peru', '秘鲁', '祕魯'], + '🇵🇭': ['Philippines', '菲律宾', '菲律賓'], + '🇵🇰': ['Pakistan', '巴基斯坦'], + '🇵🇱': ['Poland', '波兰', '波蘭', '华沙', 'Warsaw'], + '🇵🇷': ['Puerto Rico', '波多黎各'], + '🇵🇹': ['Portugal', '葡萄牙'], + '🇵🇬': ['Papua New Guinea', '巴布亚新几内亚'], + '🇵🇾': ['Paraguay', '巴拉圭'], + '🇷🇴': ['Romania', '罗马尼亚'], + '🇷🇸': ['Serbia', '塞尔维亚'], + '🇷🇪': ['Réunion', '留尼汪', '法属留尼汪'], + '🇷🇺': [ + 'Russia', + '俄罗斯', + '俄国', + '俄羅斯', + '伯力', + '莫斯科', + '圣彼得堡', + '西伯利亚', + '京俄', + '杭俄', + '廣俄', + '滬俄', + '广俄', + '沪俄', + 'Moscow', + ], + '🇸🇦': ['Saudi', '沙特阿拉伯', '沙特', 'Riyadh', '利雅得'], + '🇸🇪': ['Sweden', '瑞典', '斯德哥尔摩', 'Stockholm'], + '🇸🇬': [ + 'Singapore', + '新加坡', + '狮城', + '沪新', + '京新', + '中新', + '泉新', + '穗新', + '深新', + '杭新', + '广新', + '廣新', + '滬新', + ], + '🇸🇮': ['Slovenia', '斯洛文尼亚'], + '🇸🇰': ['Slovakia', '斯洛伐克'], + '🇹🇭': ['Thailand', '泰国', '泰國', '曼谷'], + '🇹🇳': ['Tunisia', '突尼斯'], + '🇹🇷': ['Turkey', '土耳其', '伊斯坦布尔', 'Istanbul'], + '🇹🇼': [ + 'Taiwan', + '台湾', + '臺灣', + '台灣', + '中華民國', + '中华民国', + '台北', + '台中', + '新北', + '彰化', + '台', + '臺', + 'Taipei', + 'Tai Wan', + ], + '🇺🇦': ['Ukraine', '乌克兰', '烏克蘭'], + '🇺🇸': [ + 'United States', + '美国', + 'America', + '美', + '京美', + '波特兰', + '达拉斯', + '俄勒冈', + 'Oregon', + '凤凰城', + '费利蒙', + '硅谷', + '矽谷', + '拉斯维加斯', + '洛杉矶', + '圣何塞', + '圣克拉拉', + '西雅图', + '芝加哥', + '沪美', + '哥伦布', + '纽约', + 'New York', + 'Los Angeles', + 'San Jose', + 'Sillicon Valley', + 'Michigan', + '俄亥俄', + 'Ohio', + '马纳萨斯', + 'Manassas', + '弗吉尼亚', + 'Virginia', + ], + '🇺🇾': ['Uruguay', '乌拉圭'], + '🇻🇪': ['Venezuela', '委内瑞拉'], + '🇻🇳': ['Vietnam', '越南', '胡志明'], + '🇿🇦': ['South Africa', '南非'], + '🇨🇳': [ + 'China', + '中国', + '中國', + '回国', + '回國', + '国内', + '國內', + '华东', + '华西', + '华南', + '华北', + '华中', + '江苏', + '北京', + '上海', + '广州', + '深圳', + '杭州', + '徐州', + '青岛', + '宁波', + '镇江', + ], + }; + + // 原旗帜或空 + let Flag = + name.match(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/)?.[0] || + '🏴‍☠️'; + //console.log(`oldFlag = ${Flag}`) + // 旗帜匹配 + for (let flag of Object.keys(Flags)) { + const keywords = Flags[flag]; + //console.log(`keywords = ${keywords}`) + if ( + // 不精确匹配(只要包含就算,忽略大小写) + keywords.some((keyword) => RegExp(`${keyword}`, 'i').test(name)) + ) { + if (/内蒙古/.test(name) && ['🇲🇳'].includes(flag)) { + return (Flag = '🇨🇳'); + } + return (Flag = flag); + } + } + // ISO旗帜匹配 + for (let flag of Object.keys(ISOFlags)) { + const keywords = ISOFlags[flag]; + //console.log(`keywords = ${keywords}`) + if ( + // 精确匹配(两侧均有分割) + keywords.some((keyword) => + RegExp(`(^|[^a-zA-Z])${keyword}([^a-zA-Z]|$)`).test(name), + ) + ) { + const isCN2 = + flag == '🇨🇳' && + RegExp(`(^|[^a-zA-Z])CN2([^a-zA-Z]|$)`).test(name); + if (!isCN2) { + return (Flag = flag); + } + } + } + + //console.log(`Final Flag = ${Flag}`) + return Flag; +} + +export function getISO(name) { + return ISOFlags[getFlag(name)]?.[0]; +} + +// remove flag +export function removeFlag(str) { + return str + .replace(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]|🏴‍☠️|🏳️‍🌈/g, '') + .trim(); +} + +export class MMDB { + constructor({ country, asn } = {}) { + if ($.env.isNode) { + const Reader = eval(`require("@maxmind/geoip2-node")`).Reader; + const fs = eval("require('fs')"); + const countryFile = + country || eval('process.env.SUB_STORE_MMDB_COUNTRY_PATH'); + const asnFile = asn || eval('process.env.SUB_STORE_MMDB_ASN_PATH'); + // $.info( + // `GeoLite2 Country MMDB: ${countryFile}, exists: ${fs.existsSync( + // countryFile, + // )}`, + // ); + if (countryFile) { + this.countryReader = Reader.openBuffer( + fs.readFileSync(countryFile), + ); + } + // $.info( + // `GeoLite2 ASN MMDB: ${asnFile}, exists: ${fs.existsSync( + // asnFile, + // )}`, + // ); + if (asnFile) { + if (!fs.existsSync(asnFile)) + throw new Error('GeoLite2 ASN MMDB does not exist'); + this.asnReader = Reader.openBuffer(fs.readFileSync(asnFile)); + } + } + } + geoip(ip) { + return this.countryReader?.country(ip)?.country?.isoCode; + } + ipaso(ip) { + return this.asnReader?.asn(ip)?.autonomousSystemOrganization; + } + ipasn(ip) { + return this.asnReader?.asn(ip)?.autonomousSystemNumber; + } +} diff --git a/backend/src/utils/gist.js b/backend/src/utils/gist.js new file mode 100644 index 0000000000..0aeba2537e --- /dev/null +++ b/backend/src/utils/gist.js @@ -0,0 +1,286 @@ +import { HTTP, ENV } from '@/vendor/open-api'; +import { getPolicyDescriptor } from '@/utils'; +import $ from '@/core/app'; +import { SETTINGS_KEY } from '@/constants'; + +/** + * Gist backup + */ +export default class Gist { + constructor({ token, key, syncPlatform }) { + const { isStash, isLoon, isShadowRocket, isQX } = ENV(); + const { defaultProxy, defaultTimeout: timeout } = $.read(SETTINGS_KEY); + let proxy = defaultProxy; + if ($.env.isNode) { + proxy = + proxy || eval('process.env.SUB_STORE_BACKEND_DEFAULT_PROXY'); + } + + if (syncPlatform === 'gitlab') { + this.headers = { + 'PRIVATE-TOKEN': `${token}`, + 'User-Agent': + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.141 Safari/537.36', + }; + this.http = HTTP({ + baseURL: 'https://gitlab.com/api/v4', + headers: { + ...this.headers, + ...(isStash && proxy + ? { + 'X-Stash-Selected-Proxy': + encodeURIComponent(proxy), + } + : {}), + ...(isShadowRocket && proxy + ? { 'X-Surge-Policy': proxy } + : {}), + }, + + ...(proxy ? { proxy } : {}), + ...(isLoon && proxy ? { node: proxy } : {}), + ...(isQX && proxy ? { opts: { policy: proxy } } : {}), + ...(proxy ? getPolicyDescriptor(proxy) : {}), + timeout: timeout || 8000, + + events: { + onResponse: (resp) => { + if (/^[45]/.test(String(resp.statusCode))) { + const body = JSON.parse(resp.body); + return Promise.reject( + `ERROR: ${body.message?.error ?? body.message}`, + ); + } else { + return resp; + } + }, + }, + }); + } else { + this.headers = { + Authorization: `token ${token}`, + 'User-Agent': + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.141 Safari/537.36', + }; + this.http = HTTP({ + baseURL: 'https://api.github.com', + headers: { + ...this.headers, + ...(isStash && proxy + ? { + 'X-Stash-Selected-Proxy': + encodeURIComponent(proxy), + } + : {}), + ...(isShadowRocket && proxy + ? { 'X-Surge-Policy': proxy } + : {}), + }, + + ...(proxy ? { proxy } : {}), + ...(isLoon && proxy ? { node: proxy } : {}), + ...(isQX && proxy ? { opts: { policy: proxy } } : {}), + ...(proxy ? getPolicyDescriptor(proxy) : {}), + timeout: timeout || 8000, + + events: { + onResponse: (resp) => { + if (/^[45]/.test(String(resp.statusCode))) { + return Promise.reject( + `ERROR: ${JSON.parse(resp.body).message}`, + ); + } else { + return resp; + } + }, + }, + }); + } + + this.key = key; + this.syncPlatform = syncPlatform; + } + + async locate() { + if (this.syncPlatform === 'gitlab') { + return this.http.get('/snippets').then((response) => { + const gists = JSON.parse(response.body); + + for (let g of gists) { + if (g.title === this.key) { + return g; + } + } + return; + }); + } else { + return this.http + .get('/gists?per_page=100&page=1') + .then((response) => { + const gists = JSON.parse(response.body); + $.info(`获取到当前 GitHub 用户的 gist: ${gists.length} 个`); + for (let g of gists) { + if (g.description === this.key) { + return g; + } + } + return; + }); + } + } + + async upload(input) { + if (Object.keys(input).length === 0) { + return Promise.reject('未提供需上传的文件'); + } + + const gist = await this.locate(); + + let files = input; + + if (gist?.id) { + if (this.syncPlatform === 'gitlab') { + gist.files = gist.files.reduce((acc, item) => { + acc[item.path] = item; + return acc; + }, {}); + } + // console.log(`files`, files); + // console.log(`gist`, gist.files); + let actions = []; + const result = { ...gist.files }; + Object.keys(files).map((key) => { + if (result[key]) { + if ( + files[key].content == null || + files[key].content === '' + ) { + delete result[key]; + actions.push({ + action: 'delete', + file_path: key, + }); + } else { + result[key] = files[key]; + actions.push({ + action: 'update', + file_path: key, + content: files[key].content, + }); + } + } else { + if ( + files[key].content == null || + files[key].content === '' + ) { + delete result[key]; + delete files[key]; + } else { + result[key] = files[key]; + actions.push({ + action: 'create', + file_path: key, + content: files[key].content, + }); + } + } + }); + // console.log(`result`, result); + // console.log(`files`, files); + // console.log(`actions`, actions); + + if (this.syncPlatform === 'gitlab') { + if (Object.keys(result).length === 0) { + return Promise.reject( + '本次操作将导致所有文件的内容都为空, 无法更新 snippet', + ); + } + if (Object.keys(result).length > 10) { + return Promise.reject( + '本次操作将导致 snippet 的文件数超过 10, 无法更新 snippet', + ); + } + files = actions; + return this.http.put({ + headers: { + ...this.headers, + 'Content-Type': 'application/json', + }, + url: `/snippets/${gist.id}`, + body: JSON.stringify({ files }), + }); + } else { + if (Object.keys(result).length === 0) { + return Promise.reject( + '本次操作将导致所有文件的内容都为空, 无法更新 gist', + ); + } + return this.http.patch({ + url: `/gists/${gist.id}`, + body: JSON.stringify({ files }), + }); + } + } else { + files = Object.entries(files).reduce((acc, [key, file]) => { + if (file.content !== null && file.content !== '') { + acc[key] = file; + } + return acc; + }, {}); + if (this.syncPlatform === 'gitlab') { + if (Object.keys(files).length === 0) { + return Promise.reject( + '所有文件的内容都为空, 无法创建 snippet', + ); + } + files = Object.keys(files).map((key) => ({ + file_path: key, + content: files[key].content, + })); + return this.http.post({ + headers: { + ...this.headers, + 'Content-Type': 'application/json', + }, + url: '/snippets', + body: JSON.stringify({ + title: this.key, + visibility: 'private', + files, + }), + }); + } else { + if (Object.keys(files).length === 0) { + return Promise.reject( + '所有文件的内容都为空, 无法创建 gist', + ); + } + return this.http.post({ + url: '/gists', + body: JSON.stringify({ + description: this.key, + public: false, + files, + }), + }); + } + } + } + + async download(filename) { + const gist = await this.locate(); + if (gist?.id) { + try { + const { files } = await this.http + .get(`/gists/${gist.id}`) + .then((resp) => JSON.parse(resp.body)); + const url = files[filename].raw_url; + return await this.http.get(url).then((resp) => resp.body); + } catch (err) { + return Promise.reject(err); + } + } else { + return Promise.reject(`找不到 Sub-Store Gist (${this.key})`); + } + } +} diff --git a/backend/src/utils/headers-resource-cache.js b/backend/src/utils/headers-resource-cache.js new file mode 100644 index 0000000000..a4bf92ed61 --- /dev/null +++ b/backend/src/utils/headers-resource-cache.js @@ -0,0 +1,117 @@ +import $ from '@/core/app'; +import { + HEADERS_RESOURCE_CACHE_KEY, + CHR_EXPIRATION_TIME_KEY, +} from '@/constants'; + +class ResourceCache { + constructor() { + this.expires = getExpiredTime(); + if (!$.read(HEADERS_RESOURCE_CACHE_KEY)) { + $.write('{}', HEADERS_RESOURCE_CACHE_KEY); + } + try { + this.resourceCache = JSON.parse($.read(HEADERS_RESOURCE_CACHE_KEY)); + } catch (e) { + $.error( + `解析持久化缓存中的 ${HEADERS_RESOURCE_CACHE_KEY} 失败, 重置为 {}, 错误: ${ + e?.message ?? e + }`, + ); + this.resourceCache = {}; + $.write('{}', HEADERS_RESOURCE_CACHE_KEY); + } + this._cleanup(); + } + + _cleanup() { + // clear obsolete cached resource + let clear = false; + Object.entries(this.resourceCache).forEach((entry) => { + const [id, updated] = entry; + if (!updated.time) { + // clear old version cache + delete this.resourceCache[id]; + $.delete(`#${id}`); + clear = true; + } + if (new Date().getTime() - updated.time > this.expires) { + delete this.resourceCache[id]; + clear = true; + } + }); + if (clear) this._persist(); + } + + revokeAll() { + this.resourceCache = {}; + this._persist(); + } + + _persist() { + $.write(JSON.stringify(this.resourceCache), HEADERS_RESOURCE_CACHE_KEY); + } + + get(id) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated && new Date().getTime() - updated <= this.expires) { + return this.resourceCache[id].data; + } + return null; + } + + gettime(id) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated && new Date().getTime() - updated <= this.expires) { + return this.resourceCache[id].time; + } + return null; + } + + set(id, value) { + this.resourceCache[id] = { time: new Date().getTime(), data: value }; + this._persist(); + } +} + +function getExpiredTime() { + // console.log($.read(CHR_EXPIRATION_TIME_KEY)); + if (!$.read(CHR_EXPIRATION_TIME_KEY)) { + $.write('6e4', CHR_EXPIRATION_TIME_KEY); // 1分钟 + } + let expiration = 6e4; + if ($.env.isLoon) { + const loont = { + // Loon 插件自义定 + '1\u5206\u949f': 6e4, + '5\u5206\u949f': 3e5, + '10\u5206\u949f': 6e5, + '30\u5206\u949f': 18e5, // "30分钟" + '1\u5c0f\u65f6': 36e5, + '2\u5c0f\u65f6': 72e5, + '3\u5c0f\u65f6': 108e5, + '6\u5c0f\u65f6': 216e5, + '12\u5c0f\u65f6': 432e5, + '24\u5c0f\u65f6': 864e5, + '48\u5c0f\u65f6': 1728e5, + '72\u5c0f\u65f6': 2592e5, // "72小时" + '\u53c2\u6570\u4f20\u5165': 'readcachets', // "参数输入" + }; + let intimed = $.read( + '#\u54cd\u5e94\u5934\u7f13\u5b58\u6709\u6548\u671f', + ); // Loon #响应头缓存有效期 + // console.log(intimed); + if (intimed in loont) { + expiration = loont[intimed]; + if (expiration === 'readcachets') { + expiration = intimed; + } + } + return expiration; + } else { + expiration = $.read(CHR_EXPIRATION_TIME_KEY); + return expiration; + } +} + +export default new ResourceCache(); diff --git a/backend/src/utils/index.js b/backend/src/utils/index.js new file mode 100644 index 0000000000..f771d2c4d1 --- /dev/null +++ b/backend/src/utils/index.js @@ -0,0 +1,168 @@ +import * as ipAddress from 'ip-address'; +// source: https://stackoverflow.com/a/36760050 +const IPV4_REGEX = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/; + +// source: https://ihateregex.io/expr/ipv6/ +const IPV6_REGEX = + /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/; + +function isIPv4(ip) { + return IPV4_REGEX.test(ip); +} + +function isIPv6(ip) { + return IPV6_REGEX.test(ip); +} + +function isValidPortNumber(port) { + return /^((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$/.test( + port, + ); +} + +function isNotBlank(str) { + return typeof str === 'string' && str.trim().length > 0; +} + +function getIfNotBlank(str, defaultValue) { + return isNotBlank(str) ? str : defaultValue; +} + +function isPresent(obj) { + return typeof obj !== 'undefined' && obj !== null; +} + +function getIfPresent(obj, defaultValue) { + return isPresent(obj) ? obj : defaultValue; +} + +function getPolicyDescriptor(str) { + if (!str) return {}; + return /^.+?\s*?=\s*?.+?\s*?,.+?/.test(str) + ? { + 'policy-descriptor': str, + } + : { + policy: str, + }; +} + +// const utf8ArrayToStr = +// typeof TextDecoder !== 'undefined' +// ? (v) => new TextDecoder().decode(new Uint8Array(v)) +// : (function () { +// var charCache = new Array(128); // Preallocate the cache for the common single byte chars +// var charFromCodePt = String.fromCodePoint || String.fromCharCode; +// var result = []; + +// return function (array) { +// var codePt, byte1; +// var buffLen = array.length; + +// result.length = 0; + +// for (var i = 0; i < buffLen; ) { +// byte1 = array[i++]; + +// if (byte1 <= 0x7f) { +// codePt = byte1; +// } else if (byte1 <= 0xdf) { +// codePt = ((byte1 & 0x1f) << 6) | (array[i++] & 0x3f); +// } else if (byte1 <= 0xef) { +// codePt = +// ((byte1 & 0x0f) << 12) | +// ((array[i++] & 0x3f) << 6) | +// (array[i++] & 0x3f); +// } else if (String.fromCodePoint) { +// codePt = +// ((byte1 & 0x07) << 18) | +// ((array[i++] & 0x3f) << 12) | +// ((array[i++] & 0x3f) << 6) | +// (array[i++] & 0x3f); +// } else { +// codePt = 63; // Cannot convert four byte code points, so use "?" instead +// i += 3; +// } + +// result.push( +// charCache[codePt] || +// (charCache[codePt] = charFromCodePt(codePt)), +// ); +// } + +// return result.join(''); +// }; +// })(); + +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function getRandomPort(portString) { + let portParts = portString.split(/,|\//); + let randomPart = portParts[Math.floor(Math.random() * portParts.length)]; + if (randomPart.includes('-')) { + let [min, max] = randomPart.split('-').map(Number); + return getRandomInt(min, max); + } else { + return Number(randomPart); + } +} + +function numberToString(value) { + return Number.isSafeInteger(value) + ? String(value) + : BigInt(value).toString(); +} + +function isValidUUID(uuid) { + return ( + typeof uuid === 'string' && + /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test( + uuid, + ) + ); +} + +function formatDateTime(date, format = 'YYYY-MM-DD_HH-mm-ss') { + const d = date instanceof Date ? date : new Date(date); + + if (isNaN(d.getTime())) { + return ''; + } + + const pad = (num) => String(num).padStart(2, '0'); + + const replacements = { + YYYY: d.getFullYear(), + MM: pad(d.getMonth() + 1), + DD: pad(d.getDate()), + HH: pad(d.getHours()), + mm: pad(d.getMinutes()), + ss: pad(d.getSeconds()), + }; + + return format.replace( + /YYYY|MM|DD|HH|mm|ss/g, + (match) => replacements[match], + ); +} + +export { + formatDateTime, + isValidUUID, + ipAddress, + isIPv4, + isIPv6, + isValidPortNumber, + isNotBlank, + getIfNotBlank, + isPresent, + getIfPresent, + // utf8ArrayToStr, + getPolicyDescriptor, + getRandomPort, + numberToString, +}; diff --git a/backend/src/utils/logical.js b/backend/src/utils/logical.js new file mode 100644 index 0000000000..c58cc5771c --- /dev/null +++ b/backend/src/utils/logical.js @@ -0,0 +1,17 @@ +function AND(...args) { + return args.reduce((a, b) => a.map((c, i) => b[i] && c)); +} + +function OR(...args) { + return args.reduce((a, b) => a.map((c, i) => b[i] || c)); +} + +function NOT(array) { + return array.map((c) => !c); +} + +function FULL(length, bool) { + return [...Array(length).keys()].map(() => bool); +} + +export { AND, OR, NOT, FULL }; diff --git a/backend/src/utils/migration.js b/backend/src/utils/migration.js new file mode 100644 index 0000000000..2542980d03 --- /dev/null +++ b/backend/src/utils/migration.js @@ -0,0 +1,140 @@ +import { + SUBS_KEY, + COLLECTIONS_KEY, + SCHEMA_VERSION_KEY, + ARTIFACTS_KEY, + RULES_KEY, + FILES_KEY, + TOKENS_KEY, +} from '@/constants'; +import $ from '@/core/app'; + +export default function migrate() { + migrateV2(); +} + +function migrateV2() { + const version = $.read(SCHEMA_VERSION_KEY); + if (!version) doMigrationV2(); + + // write the current version + if (version !== '2.0') { + $.write('2.0', SCHEMA_VERSION_KEY); + } +} + +function doMigrationV2() { + $.info('Start migrating...'); + // 1. migrate subscriptions + const subs = $.read(SUBS_KEY) || {}; + const newSubs = Object.values(subs).map((sub) => { + // set default source to remote + sub.source = sub.source || 'remote'; + + migrateDisplayName(sub); + migrateProcesses(sub); + return sub; + }); + $.write(newSubs, SUBS_KEY); + + // 2. migrate collections + const collections = $.read(COLLECTIONS_KEY) || {}; + const newCollections = Object.values(collections).map((collection) => { + delete collection.ua; + migrateDisplayName(collection); + migrateProcesses(collection); + return collection; + }); + $.write(newCollections, COLLECTIONS_KEY); + + // 3. migrate artifacts + const artifacts = $.read(ARTIFACTS_KEY) || {}; + const newArtifacts = Object.values(artifacts); + $.write(newArtifacts, ARTIFACTS_KEY); + + // 4. migrate rules + const rules = $.read(RULES_KEY) || {}; + const newRules = Object.values(rules); + $.write(newRules, RULES_KEY); + + // 5. migrate files + const files = $.read(FILES_KEY) || {}; + const newFiles = Object.values(files); + $.write(newFiles, FILES_KEY); + + // 6. migrate tokens + const tokens = $.read(TOKENS_KEY) || {}; + const newTokens = Object.values(tokens); + $.write(newTokens, TOKENS_KEY); + + // 7. delete builtin rules + delete $.cache.builtin; + $.info('Migration complete!'); + + function migrateDisplayName(item) { + const displayName = item['display-name']; + if (displayName) { + item.displayName = displayName; + delete item['display-name']; + } + } + + function migrateProcesses(item) { + const processes = item.process; + if (!processes || processes.length === 0) return; + const newProcesses = []; + const quickSettingOperator = { + type: 'Quick Setting Operator', + args: { + udp: 'DEFAULT', + tfo: 'DEFAULT', + scert: 'DEFAULT', + 'vmess aead': 'DEFAULT', + useless: 'DEFAULT', + }, + }; + for (const p of processes) { + if (!p.type) continue; + if (p.type === 'Useless Filter') { + quickSettingOperator.args.useless = 'ENABLED'; + } else if (p.type === 'Set Property Operator') { + const { key, value } = p.args; + switch (key) { + case 'udp': + quickSettingOperator.args.udp = value + ? 'ENABLED' + : 'DISABLED'; + break; + case 'tfo': + quickSettingOperator.args.tfo = value + ? 'ENABLED' + : 'DISABLED'; + break; + case 'skip-cert-verify': + quickSettingOperator.args.scert = value + ? 'ENABLED' + : 'DISABLED'; + break; + case 'aead': + quickSettingOperator.args['vmess aead'] = value + ? 'ENABLED' + : 'DISABLED'; + break; + } + } else if (p.type.indexOf('Keyword') !== -1) { + // drop keyword operators and keyword filters + } else if (p.type === 'Flag Operator') { + // set default args + const add = typeof p.args === 'undefined' ? true : p.args; + p.args = { + mode: add ? 'add' : 'remove', + }; + newProcesses.push(p); + } else { + newProcesses.push(p); + } + } + newProcesses.unshift(quickSettingOperator); + item.process = newProcesses; + } +} diff --git a/backend/src/utils/resource-cache.js b/backend/src/utils/resource-cache.js new file mode 100644 index 0000000000..34db7bf98d --- /dev/null +++ b/backend/src/utils/resource-cache.js @@ -0,0 +1,66 @@ +import $ from '@/core/app'; +import { CACHE_EXPIRATION_TIME_MS, RESOURCE_CACHE_KEY } from '@/constants'; + +class ResourceCache { + constructor(expires) { + this.expires = expires; + if (!$.read(RESOURCE_CACHE_KEY)) { + $.write('{}', RESOURCE_CACHE_KEY); + } + try { + this.resourceCache = JSON.parse($.read(RESOURCE_CACHE_KEY)); + } catch (e) { + $.error( + `解析持久化缓存中的 ${RESOURCE_CACHE_KEY} 失败, 重置为 {}, 错误: ${ + e?.message ?? e + }`, + ); + this.resourceCache = {}; + $.write('{}', RESOURCE_CACHE_KEY); + } + this._cleanup(); + } + + _cleanup() { + // clear obsolete cached resource + let clear = false; + Object.entries(this.resourceCache).forEach((entry) => { + const [id, updated] = entry; + if (!updated.time) { + // clear old version cache + delete this.resourceCache[id]; + $.delete(`#${id}`); + clear = true; + } + if (new Date().getTime() - updated.time > this.expires) { + delete this.resourceCache[id]; + clear = true; + } + }); + if (clear) this._persist(); + } + + revokeAll() { + this.resourceCache = {}; + this._persist(); + } + + _persist() { + $.write(JSON.stringify(this.resourceCache), RESOURCE_CACHE_KEY); + } + + get(id) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated && new Date().getTime() - updated <= this.expires) { + return this.resourceCache[id].data; + } + return null; + } + + set(id, value) { + this.resourceCache[id] = { time: new Date().getTime(), data: value }; + this._persist(); + } +} + +export default new ResourceCache(CACHE_EXPIRATION_TIME_MS); diff --git a/backend/src/utils/rs.js b/backend/src/utils/rs.js new file mode 100644 index 0000000000..bf9c465620 --- /dev/null +++ b/backend/src/utils/rs.js @@ -0,0 +1,11 @@ +import rs from 'jsrsasign'; + +export function generateFingerprint(caStr) { + const hex = rs.pemtohex(caStr); + const fingerPrint = rs.KJUR.crypto.Util.hashHex(hex, 'sha256'); + return fingerPrint.match(/.{2}/g).join(':').toUpperCase(); +} + +export default { + generateFingerprint, +}; diff --git a/backend/src/utils/script-resource-cache.js b/backend/src/utils/script-resource-cache.js new file mode 100644 index 0000000000..bf06f1494d --- /dev/null +++ b/backend/src/utils/script-resource-cache.js @@ -0,0 +1,124 @@ +import $ from '@/core/app'; +import { + SCRIPT_RESOURCE_CACHE_KEY, + CSR_EXPIRATION_TIME_KEY, +} from '@/constants'; + +class ResourceCache { + constructor() { + this.expires = getExpiredTime(); + if (!$.read(SCRIPT_RESOURCE_CACHE_KEY)) { + $.write('{}', SCRIPT_RESOURCE_CACHE_KEY); + } + try { + this.resourceCache = JSON.parse($.read(SCRIPT_RESOURCE_CACHE_KEY)); + } catch (e) { + $.error( + `解析持久化缓存中的 ${SCRIPT_RESOURCE_CACHE_KEY} 失败, 重置为 {}, 错误: ${ + e?.message ?? e + }`, + ); + this.resourceCache = {}; + $.write('{}', SCRIPT_RESOURCE_CACHE_KEY); + } + this._cleanup(); + } + + _cleanup(prefix, expires) { + // clear obsolete cached resource + let clear = false; + Object.entries(this.resourceCache).forEach((entry) => { + const [id, updated] = entry; + if (!updated.time) { + // clear old version cache + delete this.resourceCache[id]; + $.delete(`#${id}`); + clear = true; + } + if ( + new Date().getTime() - updated.time > + (expires ?? this.expires) || + (prefix && id.startsWith(prefix)) + ) { + delete this.resourceCache[id]; + clear = true; + } + }); + if (clear) this._persist(); + } + + revokeAll() { + this.resourceCache = {}; + this._persist(); + } + + _persist() { + $.write(JSON.stringify(this.resourceCache), SCRIPT_RESOURCE_CACHE_KEY); + } + + get(id, expires, remove) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated) { + if (new Date().getTime() - updated <= (expires ?? this.expires)) + return this.resourceCache[id].data; + if (remove) { + delete this.resourceCache[id]; + this._persist(); + } + } + return null; + } + + gettime(id) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated && new Date().getTime() - updated <= this.expires) { + return this.resourceCache[id].time; + } + return null; + } + + set(id, value) { + this.resourceCache[id] = { time: new Date().getTime(), data: value }; + this._persist(); + } +} + +function getExpiredTime() { + // console.log($.read(CSR_EXPIRATION_TIME_KEY)); + if (!$.read(CSR_EXPIRATION_TIME_KEY)) { + $.write('1728e5', CSR_EXPIRATION_TIME_KEY); // 48 * 3600 * 1000 + } + let expiration = 1728e5; + if ($.env.isLoon) { + const loont = { + // Loon 插件自义定 + '1\u5206\u949f': 6e4, + '5\u5206\u949f': 3e5, + '10\u5206\u949f': 6e5, + '30\u5206\u949f': 18e5, // "30分钟" + '1\u5c0f\u65f6': 36e5, + '2\u5c0f\u65f6': 72e5, + '3\u5c0f\u65f6': 108e5, + '6\u5c0f\u65f6': 216e5, + '12\u5c0f\u65f6': 432e5, + '24\u5c0f\u65f6': 864e5, + '48\u5c0f\u65f6': 1728e5, + '72\u5c0f\u65f6': 2592e5, // "72小时" + '\u53c2\u6570\u4f20\u5165': 'readcachets', // "参数输入" + }; + let intimed = $.read('#\u8282\u70b9\u7f13\u5b58\u6709\u6548\u671f'); // Loon #节点缓存有效期 + // console.log(intimed); + if (intimed in loont) { + expiration = loont[intimed]; + if (expiration === 'readcachets') { + expiration = intimed; + } + } + return expiration; + } else { + expiration = $.read(CSR_EXPIRATION_TIME_KEY); + return expiration; + } +} + +export default new ResourceCache(); diff --git a/backend/src/utils/user-agent.js b/backend/src/utils/user-agent.js new file mode 100644 index 0000000000..96e208872a --- /dev/null +++ b/backend/src/utils/user-agent.js @@ -0,0 +1,101 @@ +import gte from 'semver/functions/gte'; +import coerce from 'semver/functions/coerce'; +import $ from '@/core/app'; + +export function getUserAgentFromHeaders(headers) { + const keys = Object.keys(headers); + let UA = ''; + let ua = ''; + let accept = ''; + for (let k of keys) { + const lower = k.toLowerCase(); + if (lower === 'user-agent') { + UA = headers[k]; + ua = UA.toLowerCase(); + } else if (lower === 'accept') { + accept = headers[k]; + } + } + return { UA, ua, accept }; +} + +export function getPlatformFromUserAgent({ ua, UA, accept }) { + if (UA.indexOf('Quantumult%20X') !== -1) { + return 'QX'; + } else if (ua.indexOf('egern') !== -1) { + return 'Egern'; + } else if (UA.indexOf('Surfboard') !== -1) { + return 'Surfboard'; + } else if (UA.indexOf('Surge Mac') !== -1) { + return 'SurgeMac'; + } else if (UA.indexOf('Surge') !== -1) { + return 'Surge'; + } else if (UA.indexOf('Decar') !== -1 || UA.indexOf('Loon') !== -1) { + return 'Loon'; + } else if (UA.indexOf('Shadowrocket') !== -1) { + return 'Shadowrocket'; + } else if (UA.indexOf('Stash') !== -1) { + return 'Stash'; + } else if ( + ua === 'meta' || + (ua.indexOf('clash') !== -1 && ua.indexOf('meta') !== -1) || + ua.indexOf('clash-verge') !== -1 || + ua.indexOf('flclash') !== -1 + ) { + return 'ClashMeta'; + } else if (ua.indexOf('clash') !== -1) { + return 'Clash'; + } else if (ua.indexOf('v2ray') !== -1) { + return 'V2Ray'; + } else if (ua.indexOf('sing-box') !== -1 || ua.indexOf('singbox') !== -1) { + return 'sing-box'; + } else if (accept.indexOf('application/json') === 0) { + return 'JSON'; + } else { + return 'V2Ray'; + } +} + +export function getPlatformFromHeaders(headers) { + const { UA, ua, accept } = getUserAgentFromHeaders(headers); + return getPlatformFromUserAgent({ ua, UA, accept }); +} +export function shouldIncludeUnsupportedProxy(platform, ua) { + try { + const target = getPlatformFromUserAgent({ + UA: ua, + ua: ua.toLowerCase(), + }); + if (!['Stash', 'Egern', 'Loon'].includes(target)) { + return false; + } + const coerceVersion = coerce(ua); + $.log(JSON.stringify(coerceVersion, null, 2)); + const { version } = coerceVersion; + if ( + platform === 'Stash' && + target === 'Stash' && + gte(version, '3.1.0') + ) { + return true; + } + if ( + platform === 'Egern' && + target === 'Egern' && + gte(version, '1.29.0') + ) { + return true; + } + // Loon 的 UA 不规范, version 取出来是 build + if ( + platform === 'Loon' && + target === 'Loon' && + gte(version, '842.0.0') + ) { + return true; + } + } catch (e) { + $.error(`获取版本号失败: ${e}`); + } + return false; +} diff --git a/backend/src/utils/yaml.js b/backend/src/utils/yaml.js new file mode 100644 index 0000000000..9ea9c0e003 --- /dev/null +++ b/backend/src/utils/yaml.js @@ -0,0 +1,37 @@ +import YAML from 'static-js-yaml'; + +function retry(fn, content, ...args) { + try { + return fn(content, ...args); + } catch (e) { + return fn( + dump( + fn( + content.replace(/!\s*/g, '__SubStoreJSYAMLString__'), + ...args, + ), + ).replace(/__SubStoreJSYAMLString__/g, ''), + ...args, + ); + } +} + +export function safeLoad(content, ...args) { + return retry(YAML.safeLoad, JSON.parse(JSON.stringify(content)), ...args); +} +export function load(content, ...args) { + return retry(YAML.load, JSON.parse(JSON.stringify(content)), ...args); +} +export function safeDump(content, ...args) { + return YAML.safeDump(JSON.parse(JSON.stringify(content)), ...args); +} +export function dump(content, ...args) { + return YAML.dump(JSON.parse(JSON.stringify(content)), ...args); +} + +export default { + safeLoad, + load, + safeDump, + dump, +}; diff --git a/backend/src/vendor/express.js b/backend/src/vendor/express.js new file mode 100644 index 0000000000..95cd5dc5de --- /dev/null +++ b/backend/src/vendor/express.js @@ -0,0 +1,301 @@ +/* eslint-disable no-undef */ +import { ENV } from './open-api'; + +export default function express({ substore: $, port, host }) { + const { isNode } = ENV(); + const DEFAULT_HEADERS = { + 'Content-Type': 'text/plain;charset=UTF-8', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'POST,GET,OPTIONS,PATCH,PUT,DELETE', + 'Access-Control-Allow-Headers': + 'Origin, X-Requested-With, Content-Type, Accept', + 'X-Powered-By': 'Sub-Store', + }; + + // node support + if (isNode) { + const express_ = eval(`require("express")`); + const bodyParser = eval(`require("body-parser")`); + const app = express_(); + app.use( + bodyParser.json({ + verify: rawBodySaver, + limit: eval('process.env.SUB_STORE_BODY_JSON_LIMIT') || '1mb', + }), + ); + app.use( + bodyParser.urlencoded({ verify: rawBodySaver, extended: true }), + ); + app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' })); + app.use((_, res, next) => { + res.set(DEFAULT_HEADERS); + next(); + }); + + // adapter + app.start = () => { + const listener = app.listen(port, host, () => { + const { address, port } = listener.address(); + $.info(`[BACKEND] ${address}:${port}`); + }); + }; + return app; + } + + // route handlers + const handlers = []; + + // http methods + const METHODS_NAMES = [ + 'GET', + 'POST', + 'PUT', + 'DELETE', + 'PATCH', + 'OPTIONS', + "HEAD'", + 'ALL', + ]; + + // dispatch url to route + const dispatch = (request, start = 0) => { + let { method, url, headers, body } = request; + headers = formatHeaders(headers); + if (/json/i.test(headers['content-type'])) { + body = JSON.parse(body); + } + + method = method.toUpperCase(); + const { path, query } = extractURL(url); + + // pattern match + let handler = null; + let i; + let longestMatchedPattern = 0; + for (i = start; i < handlers.length; i++) { + if (handlers[i].method === 'ALL' || method === handlers[i].method) { + const { pattern } = handlers[i]; + if (patternMatched(pattern, path)) { + if (pattern.split('/').length > longestMatchedPattern) { + handler = handlers[i]; + longestMatchedPattern = pattern.split('/').length; + } + } + } + } + if (handler) { + // dispatch to next handler + const next = () => { + dispatch(method, url, i); + }; + const req = { + method, + url, + path, + query, + params: extractPathParams(handler.pattern, path), + headers, + body, + }; + const res = Response(); + const cb = handler.callback; + + const errFunc = (err) => { + res.status(500).json({ + status: 'failed', + message: `Internal Server Error: ${err}`, + }); + }; + + if (cb.constructor.name === 'AsyncFunction') { + cb(req, res, next).catch(errFunc); + } else { + try { + cb(req, res, next); + } catch (err) { + errFunc(err); + } + } + } else { + // no route, return 404 + const res = Response(); + res.status(404).json({ + status: 'failed', + message: 'ERROR: 404 not found', + }); + } + }; + + const app = {}; + + // attach http methods + METHODS_NAMES.forEach((method) => { + app[method.toLowerCase()] = (pattern, callback) => { + // add handler + handlers.push({ method, pattern, callback }); + }; + }); + + // chainable route + app.route = (pattern) => { + const chainApp = {}; + METHODS_NAMES.forEach((method) => { + chainApp[method.toLowerCase()] = (callback) => { + // add handler + handlers.push({ method, pattern, callback }); + return chainApp; + }; + }); + return chainApp; + }; + + // start service + app.start = () => { + dispatch($request); + }; + + return app; + + /************************************************ + Utility Functions + *************************************************/ + function rawBodySaver(req, res, buf, encoding) { + if (buf && buf.length) { + req.rawBody = buf.toString(encoding || 'utf8'); + } + } + + function Response() { + let statusCode = 200; + const { isQX, isLoon, isSurge, isGUIforCores } = ENV(); + const headers = DEFAULT_HEADERS; + const STATUS_CODE_MAP = { + 200: 'HTTP/1.1 200 OK', + 201: 'HTTP/1.1 201 Created', + 302: 'HTTP/1.1 302 Found', + 307: 'HTTP/1.1 307 Temporary Redirect', + 308: 'HTTP/1.1 308 Permanent Redirect', + 404: 'HTTP/1.1 404 Not Found', + 500: 'HTTP/1.1 500 Internal Server Error', + }; + return new (class { + status(code) { + statusCode = code; + return this; + } + + send(body = '') { + const response = { + status: isQX ? STATUS_CODE_MAP[statusCode] : statusCode, + body, + headers, + }; + if (isQX || isGUIforCores) { + $done(response); + } else if (isLoon || isSurge) { + $done({ + response, + }); + } + } + + end() { + this.send(); + } + + html(data) { + this.set('Content-Type', 'text/html;charset=UTF-8'); + this.send(data); + } + + json(data) { + this.set('Content-Type', 'application/json;charset=UTF-8'); + this.send(JSON.stringify(data)); + } + + set(key, val) { + headers[key] = val; + return this; + } + })(); + } +} + +function formatHeaders(headers) { + const result = {}; + for (const k of Object.keys(headers)) { + result[k.toLowerCase()] = headers[k]; + } + return result; +} + +function patternMatched(pattern, path) { + if (pattern instanceof RegExp && pattern.test(path)) { + return true; + } else { + // root pattern, match all + if (pattern === '/') return true; + // normal string pattern + if (pattern.indexOf(':') === -1) { + const spath = path.split('/'); + const spattern = pattern.split('/'); + for (let i = 0; i < spattern.length; i++) { + if (spath[i] !== spattern[i]) { + return false; + } + } + return true; + } else if (extractPathParams(pattern, path)) { + // string pattern with path parameters + return true; + } + } + return false; +} + +function extractURL(url) { + // extract path + const match = url.match(/https?:\/\/[^/]+(\/[^?]*)/) || []; + const path = match[1] || '/'; + + // extract query string + const split = url.indexOf('?'); + const query = {}; + if (split !== -1) { + let hashes = url.slice(url.indexOf('?') + 1).split('&'); + for (let i = 0; i < hashes.length; i++) { + const hash = hashes[i].split('='); + query[hash[0]] = hash[1]; + } + } + return { + path, + query, + }; +} + +function extractPathParams(pattern, path) { + if (pattern.indexOf(':') === -1) { + return null; + } else { + const params = {}; + for (let i = 0, j = 0; i < pattern.length; i++, j++) { + if (pattern[i] === ':') { + let key = []; + let val = []; + while (pattern[++i] !== '/' && i < pattern.length) { + key.push(pattern[i]); + } + while (path[j] !== '/' && j < path.length) { + val.push(path[j++]); + } + params[key.join('')] = val.join(''); + } else { + if (pattern[i] !== path[j]) { + return null; + } + } + } + return params; + } +} diff --git a/backend/src/vendor/md5.js b/backend/src/vendor/md5.js new file mode 100644 index 0000000000..9bbcd08170 --- /dev/null +++ b/backend/src/vendor/md5.js @@ -0,0 +1,387 @@ +/* + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ''; /* base-64 pad character. "=" for strict RFC compliance */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +export function hex_md5(s) { + return rstr2hex(rstr_md5(str2rstr_utf8(s))); +} + +export function b64_md5(s) { + return rstr2b64(rstr_md5(str2rstr_utf8(s))); +} + +export function any_md5(s, e) { + return rstr2any(rstr_md5(str2rstr_utf8(s)), e); +} + +export function hex_hmac_md5(k, d) { + return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); +} + +export function b64_hmac_md5(k, d) { + return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); +} + +export function any_hmac_md5(k, d, e) { + return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); +} + +/* + * Perform a simple self-test to see if the VM is working + */ +function md5_vm_test() { + return hex_md5('abc').toLowerCase() == '900150983cd24fb0d6963f7d28e17f72'; +} + +/* + * Calculate the MD5 of a raw string + */ +function rstr_md5(s) { + return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); +} + +/* + * Calculate the HMAC-MD5, of a key and some data (raw strings) + */ +function rstr_hmac_md5(key, data) { + var bkey = rstr2binl(key); + if (bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); + + var ipad = Array(16), + opad = Array(16); + for (var i = 0; i < 16; i++) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5c5c5c5c; + } + + var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); + return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); +} + +/* + * Convert a raw string to a hex string + */ +function rstr2hex(input) { + try { + hexcase; + } catch (e) { + hexcase = 0; + } + var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef'; + var output = ''; + var x; + for (var i = 0; i < input.length; i++) { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0f) + hex_tab.charAt(x & 0x0f); + } + return output; +} + +/* + * Convert a raw string to a base-64 string + */ +function rstr2b64(input) { + try { + b64pad; + } catch (e) { + b64pad = ''; + } + var tab = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + var output = ''; + var len = input.length; + for (var i = 0; i < len; i += 3) { + var triplet = + (input.charCodeAt(i) << 16) | + (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | + (i + 2 < len ? input.charCodeAt(i + 2) : 0); + for (var j = 0; j < 4; j++) { + if (i * 8 + j * 6 > input.length * 8) output += b64pad; + else output += tab.charAt((triplet >>> (6 * (3 - j))) & 0x3f); + } + } + return output; +} + +/* + * Convert a raw string to an arbitrary string encoding + */ +function rstr2any(input, encoding) { + var divisor = encoding.length; + var i, j, q, x, quotient; + + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + var dividend = Array(Math.ceil(input.length / 2)); + for (i = 0; i < dividend.length; i++) { + dividend[i] = + (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } + + /* + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. All remainders are stored for later + * use. + */ + var full_length = Math.ceil( + (input.length * 8) / (Math.log(encoding.length) / Math.log(2)), + ); + var remainders = Array(full_length); + for (j = 0; j < full_length; j++) { + quotient = Array(); + x = 0; + for (i = 0; i < dividend.length; i++) { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if (quotient.length > 0 || q > 0) quotient[quotient.length] = q; + } + remainders[j] = x; + dividend = quotient; + } + + /* Convert the remainders to the output string */ + var output = ''; + for (i = remainders.length - 1; i >= 0; i--) + output += encoding.charAt(remainders[i]); + + return output; +} + +/* + * Encode a string as utf-8. + * For efficiency, this assumes the input is valid utf-16. + */ +function str2rstr_utf8(input) { + var output = ''; + var i = -1; + var x, y; + + while (++i < input.length) { + /* Decode utf-16 surrogate pairs */ + x = input.charCodeAt(i); + y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; + if (0xd800 <= x && x <= 0xdbff && 0xdc00 <= y && y <= 0xdfff) { + x = 0x10000 + ((x & 0x03ff) << 10) + (y & 0x03ff); + i++; + } + + /* Encode output as utf-8 */ + if (x <= 0x7f) output += String.fromCharCode(x); + else if (x <= 0x7ff) + output += String.fromCharCode( + 0xc0 | ((x >>> 6) & 0x1f), + 0x80 | (x & 0x3f), + ); + else if (x <= 0xffff) + output += String.fromCharCode( + 0xe0 | ((x >>> 12) & 0x0f), + 0x80 | ((x >>> 6) & 0x3f), + 0x80 | (x & 0x3f), + ); + else if (x <= 0x1fffff) + output += String.fromCharCode( + 0xf0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3f), + 0x80 | ((x >>> 6) & 0x3f), + 0x80 | (x & 0x3f), + ); + } + return output; +} + +/* + * Encode a string as utf-16 + */ +function str2rstr_utf16le(input) { + var output = ''; + for (var i = 0; i < input.length; i++) + output += String.fromCharCode( + input.charCodeAt(i) & 0xff, + (input.charCodeAt(i) >>> 8) & 0xff, + ); + return output; +} + +function str2rstr_utf16be(input) { + var output = ''; + for (var i = 0; i < input.length; i++) + output += String.fromCharCode( + (input.charCodeAt(i) >>> 8) & 0xff, + input.charCodeAt(i) & 0xff, + ); + return output; +} + +/* + * Convert a raw string to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ +function rstr2binl(input) { + var output = Array(input.length >> 2); + for (var i = 0; i < output.length; i++) output[i] = 0; + for (var i = 0; i < input.length * 8; i += 8) + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32; + return output; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2rstr(input) { + var output = ''; + for (var i = 0; i < input.length * 32; i += 8) + output += String.fromCharCode((input[i >> 5] >>> i % 32) & 0xff); + return output; +} + +/* + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ +function binl_md5(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << len % 32; + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + for (var i = 0; i < x.length; i += 16) { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + + a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); + d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); + d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return Array(a, b, c, d); +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn(q, a, b, x, s, t) { + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); +} + +function md5_ff(a, b, c, d, x, s, t) { + return md5_cmn((b & c) | (~b & d), a, b, x, s, t); +} + +function md5_gg(a, b, c, d, x, s, t) { + return md5_cmn((b & d) | (c & ~d), a, b, x, s, t); +} + +function md5_hh(a, b, c, d, x, s, t) { + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} + +function md5_ii(a, b, c, d, x, s, t) { + return md5_cmn(c ^ (b | ~d), a, b, x, s, t); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) { + var lsw = (x & 0xffff) + (y & 0xffff); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xffff); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); +} diff --git a/backend/src/vendor/open-api.js b/backend/src/vendor/open-api.js new file mode 100644 index 0000000000..d73a0c7b67 --- /dev/null +++ b/backend/src/vendor/open-api.js @@ -0,0 +1,508 @@ +/* eslint-disable no-undef */ +const isQX = typeof $task !== 'undefined'; +const isLoon = typeof $loon !== 'undefined'; +const isSurge = typeof $httpClient !== 'undefined' && !isLoon; +const isNode = eval(`typeof process !== "undefined"`); // eval is needed in order to avoid browserify processing +const isStash = + 'undefined' !== typeof $environment && $environment['stash-version']; +const isShadowRocket = 'undefined' !== typeof $rocket; +const isEgern = 'object' == typeof egern; +const isLanceX = 'undefined' != typeof $native; +const isGUIforCores = typeof $Plugins !== 'undefined'; + +export class OpenAPI { + constructor(name = 'untitled', debug = false) { + this.name = name; + this.debug = debug; + + this.http = HTTP(); + this.env = ENV(); + + if (isNode) { + const dotenv = eval(`require("dotenv")`); + dotenv.config(); + } + this.node = (() => { + if (isNode) { + const fs = eval("require('fs')"); + + return { + fs, + }; + } else { + return null; + } + })(); + this.initCache(); + + const delay = (t, v) => + new Promise(function (resolve) { + setTimeout(resolve.bind(null, v), t); + }); + + Promise.prototype.delay = async function (t) { + const v = await this; + return await delay(t, v); + }; + } + + // persistence + // initialize cache + initCache() { + if (isQX) + this.cache = JSON.parse($prefs.valueForKey(this.name) || '{}'); + if (isLoon || isSurge) + this.cache = JSON.parse($persistentStore.read(this.name) || '{}'); + if (isGUIforCores) + this.cache = JSON.parse( + $Plugins.SubStoreCache.get(this.name) || '{}', + ); + if (isNode) { + // create a json for root cache + const basePath = + eval('process.env.SUB_STORE_DATA_BASE_PATH') || '.'; + let rootPath = `${basePath}/root.json`; + + this.log(`Root path: ${rootPath}`); + if (!this.node.fs.existsSync(rootPath)) { + this.node.fs.writeFileSync(rootPath, JSON.stringify({}), { + flag: 'wx', + }); + this.root = {}; + } else { + this.root = JSON.parse( + this.node.fs.readFileSync(`${rootPath}`), + ); + } + + // create a json file with the given name if not exists + let fpath = `${basePath}/${this.name}.json`; + this.log(`Data path: ${fpath}`); + if (!this.node.fs.existsSync(fpath)) { + this.node.fs.writeFileSync(fpath, JSON.stringify({}), { + flag: 'wx', + }); + this.cache = {}; + } else { + this.cache = JSON.parse(this.node.fs.readFileSync(`${fpath}`)); + } + } + } + + // store cache + persistCache() { + const data = JSON.stringify(this.cache, null, 2); + if (isQX) $prefs.setValueForKey(data, this.name); + if (isLoon || isSurge) $persistentStore.write(data, this.name); + if (isGUIforCores) $Plugins.SubStoreCache.set(this.name, data); + if (isNode) { + const basePath = + eval('process.env.SUB_STORE_DATA_BASE_PATH') || '.'; + + this.node.fs.writeFileSync( + `${basePath}/${this.name}.json`, + data, + { flag: 'w' }, + (err) => console.log(err), + ); + this.node.fs.writeFileSync( + `${basePath}/root.json`, + JSON.stringify(this.root, null, 2), + { flag: 'w' }, + (err) => console.log(err), + ); + } + } + + write(data, key) { + this.log(`SET ${key}`); + if (key.indexOf('#') !== -1) { + key = key.substr(1); + if (isSurge || isLoon) { + return $persistentStore.write(data, key); + } + if (isQX) { + return $prefs.setValueForKey(data, key); + } + if (isNode) { + this.root[key] = data; + } + if (isGUIforCores) { + return $Plugins.SubStoreCache.set(key, data); + } + } else { + this.cache[key] = data; + } + this.persistCache(); + } + + read(key) { + this.log(`READ ${key}`); + if (key.indexOf('#') !== -1) { + key = key.substr(1); + if (isSurge || isLoon) { + return $persistentStore.read(key); + } + if (isQX) { + return $prefs.valueForKey(key); + } + if (isNode) { + return this.root[key]; + } + if (isGUIforCores) { + return $Plugins.SubStoreCache.get(key); + } + } else { + return this.cache[key]; + } + } + + delete(key) { + this.log(`DELETE ${key}`); + if (key.indexOf('#') !== -1) { + key = key.substr(1); + if (isSurge || isLoon) { + return $persistentStore.write(null, key); + } + if (isQX) { + return $prefs.removeValueForKey(key); + } + if (isNode) { + delete this.root[key]; + } + if (isGUIforCores) { + return $Plugins.SubStoreCache.remove(key); + } + } else { + delete this.cache[key]; + } + this.persistCache(); + } + + // notification + notify(title, subtitle = '', content = '', options = {}) { + const openURL = options['open-url']; + const mediaURL = options['media-url']; + + if (isQX) $notify(title, subtitle, content, options); + if (isSurge) { + $notification.post( + title, + subtitle, + content + `${mediaURL ? '\n多媒体:' + mediaURL : ''}`, + { + url: openURL, + }, + ); + } + if (isLoon) { + let opts = {}; + if (openURL) opts['openUrl'] = openURL; + if (mediaURL) opts['mediaUrl'] = mediaURL; + if (JSON.stringify(opts) === '{}') { + $notification.post(title, subtitle, content); + } else { + $notification.post(title, subtitle, content, opts); + } + } + if (isNode) { + const content_ = + content + + (openURL ? `\n点击跳转: ${openURL}` : '') + + (mediaURL ? `\n多媒体: ${mediaURL}` : ''); + console.log(`${title}\n${subtitle}\n${content_}\n\n`); + + let push = eval('process.env.SUB_STORE_PUSH_SERVICE'); + if (push) { + const url = push + .replace( + '[推送标题]', + encodeURIComponent(title || 'Sub-Store'), + ) + .replace( + '[推送内容]', + encodeURIComponent( + [subtitle, content_].map((i) => i).join('\n'), + ), + ); + const $http = HTTP(); + $http + .get({ url }) + .then((resp) => { + console.log( + `[Push Service] URL: ${url}\nRES: ${resp.statusCode} ${resp.body}`, + ); + }) + .catch((e) => { + console.log(`[Push Service] URL: ${url}\nERROR: ${e}`); + }); + } + } + if (isGUIforCores) { + $Plugins.Notify(title, subtitle + '\n' + content); + } + } + + // other helper functions + log(msg) { + if (this.debug) console.log(`[${this.name}] LOG: ${msg}`); + } + + info(msg) { + console.log(`[${this.name}] INFO: ${msg}`); + } + + error(msg) { + console.log(`[${this.name}] ERROR: ${msg}`); + } + + wait(millisec) { + return new Promise((resolve) => setTimeout(resolve, millisec)); + } + + done(value = {}) { + if (isQX || isLoon || isSurge || isGUIforCores) { + $done(value); + } else if (isNode) { + if (typeof $context !== 'undefined') { + $context.headers = value.headers; + $context.statusCode = value.statusCode; + $context.body = value.body; + } + } + } +} + +export function ENV() { + return { + isQX, + isLoon, + isSurge, + isNode, + isStash, + isShadowRocket, + isEgern, + isLanceX, + isGUIforCores, + }; +} + +export function HTTP(defaultOptions = { baseURL: '' }) { + const { isQX, isLoon, isSurge, isNode, isGUIforCores } = ENV(); + const methods = [ + 'GET', + 'POST', + 'PUT', + 'DELETE', + 'HEAD', + 'OPTIONS', + 'PATCH', + ]; + const URL_REGEX = + /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/; + + function send(method, options) { + options = typeof options === 'string' ? { url: options } : options; + const baseURL = defaultOptions.baseURL; + if (baseURL && !URL_REGEX.test(options.url || '')) { + options.url = baseURL ? baseURL + options.url : options.url; + } + options = { ...defaultOptions, ...options }; + const timeout = options.timeout; + const events = { + ...{ + onRequest: () => {}, + onResponse: (resp) => resp, + onTimeout: () => {}, + }, + ...options.events, + }; + + events.onRequest(method, options); + + if (options.node) { + // Surge & Loon allow connecting to a server using a specified proxy node + if (isSurge) { + const build = $environment['surge-build']; + if (build && parseInt(build) >= 2407) { + options['policy-descriptor'] = options.node; + delete options.node; + } + } + } + + let worker; + if (isQX) { + worker = $task.fetch({ + method, + url: options.url, + headers: options.headers, + body: options.body, + opts: options.opts, + }); + } else if (isLoon || isSurge || isNode) { + worker = new Promise(async (resolve, reject) => { + const body = options.body; + const opts = JSON.parse(JSON.stringify(options)); + opts.body = body; + opts.timeout = opts.timeout || 8000; + if (opts.timeout) { + opts.timeout++; + if (isNaN(opts.timeout)) { + opts.timeout = 8000; + } + if (!isNode) { + let unit = 'ms'; + // 这些客户端单位为 s + if (isSurge || isStash || isShadowRocket) { + opts.timeout = Math.ceil(opts.timeout / 1000); + unit = 's'; + } + // Loon 为 ms + // console.log(`[httpClient timeout] ${opts.timeout}${unit}`); + } + } + if (isNode) { + const undici = eval("require('undici')"); + const { + ProxyAgent, + EnvHttpProxyAgent, + request, + interceptors, + } = undici; + const agentOpts = { + connect: { + rejectUnauthorized: + opts.strictSSL === false || + opts.insecure === true + ? false + : true, + }, + bodyTimeout: opts.timeout, + headersTimeout: opts.timeout, + }; + try { + const url = new URL(opts.url); + if (url.username || url.password) { + opts.headers = { + ...(opts.headers || {}), + Authorization: `Basic ${Buffer.from( + `${url.username || ''}:${ + url.password || '' + }`, + ).toString('base64')}`, + }; + } + const response = await request(opts.url, { + ...opts, + method: method.toUpperCase(), + dispatcher: (opts.proxy + ? new ProxyAgent({ + ...agentOpts, + uri: opts.proxy, + }) + : new EnvHttpProxyAgent(agentOpts) + ).compose( + interceptors.redirect({ + maxRedirections: 3, + throwOnMaxRedirects: true, + }), + ), + }); + resolve({ + statusCode: response.statusCode, + headers: response.headers, + body: + opts.encoding === null + ? await response.body.arrayBuffer() + : await response.body.text(), + }); + } catch (e) { + reject(e); + } + } else { + $httpClient[method.toLowerCase()]( + opts, + (err, response, body) => { + // if (err) { + // console.log(err); + // } else { + // console.log({ + // statusCode: + // response.status || response.statusCode, + // headers: response.headers, + // body, + // }); + // } + + if (err) reject(err); + else + resolve({ + statusCode: + response.status || response.statusCode, + headers: response.headers, + body, + }); + }, + ); + } + }); + } else if (isGUIforCores) { + worker = new Promise(async (resolve, reject) => { + try { + const response = await $Plugins.Requests({ + method, + url: options.url, + headers: options.headers, + body: options.body, + options: { + Proxy: options.proxy, + Timeout: options.timeout + ? options.timeout / 1000 + : 15, + }, + }); + resolve({ + statusCode: response.status, + headers: response.headers, + body: response.body, + }); + } catch (error) { + reject(error); + } + }); + } + + let timeoutid; + + const timer = timeout + ? new Promise((_, reject) => { + // console.log(`[request timeout] ${timeout}ms`); + timeoutid = setTimeout(() => { + events.onTimeout(); + return reject( + `${method} URL: ${options.url} exceeds the timeout ${timeout} ms`, + ); + }, timeout); + }) + : null; + + return ( + timer + ? Promise.race([timer, worker]).then((res) => { + if (typeof clearTimeout !== 'undefined') { + clearTimeout(timeoutid); + } + return res; + }) + : worker + ).then((resp) => events.onResponse(resp)); + } + + const http = {}; + methods.forEach( + (method) => + (http[method.toLowerCase()] = (options) => send(method, options)), + ); + return http; +} diff --git a/backend/sub-store.js b/backend/sub-store.js deleted file mode 100644 index cbd9691b97..0000000000 --- a/backend/sub-store.js +++ /dev/null @@ -1,2420 +0,0 @@ -/** - * Sub-Store v0.1 (Backend only) - * @Author: Peng-YM - * @Description: - * 适用于QX,Loon,Surge的订阅管理工具。 - * - 功能 - * 1. 订阅转换,支持SS, SSR, V2RayN, QX, Loon, Surge格式的互相转换。 - * 2. 节点过滤,重命名,排序等。 - * 3. 订阅拆分,组合。 - */ - -const $ = API("sub-store"); - -// Constants -const SUBS_KEY = "subs"; -const COLLECTIONS_KEY = "collections"; - -// SOME INITIALIZATIONS -if (!$.read(SUBS_KEY)) $.write({}, SUBS_KEY); -if (!$.read(COLLECTIONS_KEY)) $.write({}, COLLECTIONS_KEY); - -// BACKEND API -const $app = express(); - -// subscriptions -$app.get("/download/:name", downloadSub) - -$app.route("/sub/:name") - .get(getSub) - .patch(updateSub) - .delete(deleteSub); - -$app.route("/sub") - .get(getAllSubs) - .post(newSub) - .delete(deleteAllSubs); - -// collections -$app.get("/download/collection/:name", downloadCollection); -$app.route("/collection/:name") - .get(getCollection) - .patch(updateCollection) - .delete(deleteCollection); -$app.route("/collection") - .get(getAllCollections) - .post(newCollection) - .delete(deleteAllCollections); - -$app.all("/", (req, res) => { - res.send("Hello from Sub-Store! Made with ❤️ by Peng-YM.") -}); - -$app.start(); - -// SOME CONSTANTS -const FALL_BACK_TARGET = "Raw"; -const DEFAULT_SUPPORTED_PLATFORMS = { - QX: true, - Loon: true, - Surge: true, - Raw: true -} -const AVAILABLE_FILTERS = { - "Keyword Filter": KeywordFilter, - "Discard Keyword Filter": DiscardKeywordFilter, - "Useless Filter": UselessFilter, - "Region Filter": RegionFilter, - "Regex Filter": RegexFilter, - "Discard Regex Filter": DiscardRegexFilter, - "Type Filter": TypeFilter, - "Script Filter": ScriptFilter -} - -const AVAILABLE_OPERATORS = { - "Set Property Operator": SetPropertyOperator, - "Flag Operator": FlagOperator, - "Sort Operator": SortOperator, - "Keyword Sort Operator": KeywordSortOperator, - "Keyword Rename Operator": KeywordRenameOperator, - "Keyword Delete Operator": KeywordDeleteOperator, - "Regex Rename Operator": RegexRenameOperator, - "Regex Delete Operator": RegexDeleteOperator, - "Script Operator": ScriptOperator -} - -/**************************** API -- Subscriptions ***************************************/ -// download subscription, for APP only -async function downloadSub(req, res) { - const {name} = req.params; - const platform = getPlatformFromHeaders(req.headers); - const allSubs = $.read(SUBS_KEY); - if (allSubs[name]) { - const sub = allSubs[name]; - try { - const output = await parseSub(sub, platform); - res.send(output); - } catch (err) { - $.notify('[Sub-Store]', '❌ 无法获取订阅!', `错误信息:${err}`) - res.status(500).json({ - status: "failed", - message: err - }); - } - } else { - res.status(404).json({ - status: "failed", - message: `订阅${name}不存在!` - }); - } -} - -async function parseSub(sub, platform) { - // download from url - const raw = await $.http.get(sub.url).then(resp => resp.body).catch(err => { - throw new Error(err); - }); - console.log("======================================================================="); - console.log(`Processing subscription: ${sub.name}, target platform ==> ${platform}.`); - const $parser = ProxyParser(platform); - let proxies = $parser.parse(raw); - - // filters - const $filter = ProxyFilter(); - // operators - const $operator = ProxyOperator(); - - for (const item of sub.process || []) { - if (item.type.indexOf("Script") !== -1) { - if (item.args && item.args[0].indexOf("http") !== -1) { - // if this is remote script - item.args[0] = await $.http.get(item.args[0]).then(resp => resp.body).catch(err => { - throw new Error(`Error when downloading remote script: ${item.args[0]}.\n Reason: ${err}`); - }); - } - } - if (item.type.indexOf("Filter") !== -1) { - const filter = AVAILABLE_FILTERS[item.type]; - if (filter) { - $filter.addFilters(filter(...(item.args || []))); - proxies = $filter.process(proxies); - console.log(`Applying filter "${item.type}" with arguments:\n >>> ${item.args || "None"}`); - } - } else if (item.type.indexOf("Operator") !== -1) { - const operator = AVAILABLE_OPERATORS[item.type]; - if (operator) { - $operator.addOperators(operator(...(item.args || []))); - proxies = $operator.process(proxies); - console.log(`Applying operator "${item.type}" with arguments: \n >>> ${item.args || "None"}`); - } - } - } - return $parser.produce(proxies); -} - -// Subscriptions -async function getSub(req, res) { - const {name} = req.params; - const sub = $.read(SUBS_KEY)[name]; - if (sub) { - res.json({ - status: "success", - data: sub - }); - } else { - res.status(404).json({ - status: "failed", - message: `未找到订阅:${name}!` - }); - } -} - -async function newSub(req, res) { - const sub = req.body; - const allSubs = $.read(SUBS_KEY); - if (allSubs[sub.name]) { - res.status(500).json({ - status: "failed", - message: `订阅${sub.name}已存在!` - }); - } - // validate name - if (/^[\w-_]*$/.test(sub.name)) { - allSubs[sub.name] = sub; - $.write(allSubs, SUBS_KEY); - res.status(201).json({ - status: "success", - data: sub - }); - } else { - res.status(500).json({ - status: "failed", - message: `订阅名称 ${sub.name} 中含有非法字符!名称中只能包含英文字母、数字、下划线、横杠。` - }) - } -} - -async function updateSub(req, res) { - const {name} = req.params; - let sub = req.body; - const allSubs = $.read(SUBS_KEY); - if (allSubs[name]) { - const newSub = { - ...allSubs[name], - ...sub - }; - allSubs[name] = newSub; - $.write(allSubs, SUBS_KEY); - res.json({ - status: "success", - data: newSub - }) - } else { - res.status(500).json({ - status: "failed", - message: `订阅${name}不存在,无法更新!` - }); - } -} - -async function deleteSub(req, res) { - const {name} = req.params; - let allSubs = $.read(SUBS_KEY); - delete allSubs[name]; - $.write(allSubs, SUBS_KEY); - res.json({ - status: "success" - }); -} - -async function getAllSubs(req, res) { - const allSubs = $.read(SUBS_KEY); - res.json({ - status: "success", - data: Object.keys(allSubs) - }); -} - -async function deleteAllSubs(req, res) { - $.write({}, SUBS_KEY); - res.json({ - status: "success" - }); -} - -// Collections -async function downloadCollection(req, res) { - const {name} = req.params; - const collection = $.read(COLLECTIONS_KEY)[name]; - const platform = getPlatformFromHeaders(req.headers); - if (collection) { - const subs = collection.subscriptions || []; - const output = await Promise.all(subs.map(async id => { - const sub = $.read(SUBS_KEY)[id]; - try { - return parseSub(sub, platform); - } catch (err) { - console.log(`ERROR when process subscription: ${id}`); - return ""; - } - })); - res.send(output.join("\n")); - } else { - $.notify('[Sub-Store]', `❌ 未找到订阅集:${name}!`) - res.status(404).json({ - status: "failed", - message: `❌ 未找到订阅集:${name}!` - }); - } -} - -async function getCollection(req, res) { - const {name} = req.params; - const collection = $.read(COLLECTIONS_KEY)[name]; - if (collection) { - res.json({ - status: "success", - data: collection - }); - } else { - res.status(404).json({ - status: "failed", - message: `未找到订阅集:${name}!` - }); - } -} - -async function newCollection(req, res) { - const collection = req.body; - const allCol = $.read(COLLECTIONS_KEY); - if (allCol[collection.name]) { - res.status(500).json({ - status: "failed", - message: `订阅集${collection.name}已存在!` - }); - } - // validate name - if (/^[\w-_]*$/.test(collection.name)) { - allCol[collection.name] = collection; - $.write(allCol, COLLECTIONS_KEY); - res.status(201).json({ - status: "success", - data: collection - }); - } else { - res.status(500).json({ - status: "failed", - message: `订阅集名称 ${collection.name} 中含有非法字符!名称中只能包含英文字母、数字、下划线、横杠。` - }) - } -} - -async function updateCollection(req, res) { - const {name} = req.params; - let collection = req.body; - const allCol = $.read(COLLECTIONS_KEY); - if (allCol[name]) { - const newCol = { - ...allCol[name], - ...collection - }; - allCol[name] = newCol; - $.write(allCol, COLLECTIONS_KEY); - res.json({ - status: "success", - data: newCol - }) - } else { - res.status(500).json({ - status: "failed", - message: `订阅集${name}不存在,无法更新!` - }); - } -} - -async function deleteCollection(req, res) { - const {name} = req.params; - let allCol = $.read(COLLECTIONS_KEY); - delete allCol[name]; - $.write(allCol, COLLECTIONS_KEY); - res.json({ - status: "success" - }); -} - -async function getAllCollections(req, res) { - const allCols = $.read(COLLECTIONS_KEY); - res.json({ - status: "success", - data: Object.keys(allCols) - }); -} - -async function deleteAllCollections(req, res) { - $.write({}, COLLECTIONS_KEY); - res.json({ - status: "success" - }); -} - -/**************************** Proxy Handlers ***************************************/ -function ProxyParser(targetPlatform) { - // parser collections - const parsers = []; - const producers = []; - - function addParsers(...args) { - args.forEach(a => parsers.push(a())); - } - - function addProducers(...args) { - args.forEach(a => producers.push(a())) - } - - function parse(raw) { - raw = preprocessing(raw); - const lines = raw.split("\n"); - const result = []; - // convert to json format - for (let line of lines) { - line = line.trim(); - if (line.length === 0) continue; // skip empty line - if (line.startsWith("#")) continue; // skip comments - let matched = false; - for (const p of parsers) { - const {patternTest, func} = p; - - // some lines with weird format may produce errors! - let patternMatched; - try { - patternMatched = patternTest(line); - } catch (err) { - patternMatched = false; - } - - if (patternMatched) { - matched = true; - // run parser safely. - try { - const proxy = func(line); - if (!proxy) { - // failed to parse this line - console.log(`ERROR: parser return nothing for \n${line}\n`); - break; - } - // skip unsupported proxies - // if proxy.supported is undefined, assume that all platforms are supported. - if (typeof proxy.supported === 'undefined' || proxy.supported[targetPlatform]) { - delete proxy.supported; - result.push(proxy); - break; - } - } catch (err) { - console.log(`ERROR: Failed to parse line: \n ${line}\n Reason: ${err}`); - } - } - } - if (!matched) { - console.log(`ERROR: Failed to find a rule to parse line: \n${line}\n`); - } - } - if (result.length === 0) { - throw new Error(`ERROR: Input does not contains any valid node for platform ${targetPlatform}`) - } - return result; - } - - function produce(proxies) { - for (const p of producers) { - if (p.targetPlatform === targetPlatform) { - return proxies.map(proxy => { - try { - return p.output(proxy) - } catch (err) { - console.log(`ERROR: cannot produce proxy: ${JSON.stringify(proxy)}\nReason: ${err}`); - return ""; - } - }).join("\n"); - } - } - throw new Error(`Cannot find any producer for target platform: ${targetPlatform}`); - } - - // preprocess raw input - function preprocessing(raw) { - let output; - if (raw.indexOf("DOCTYPE html") !== -1) { - // HTML format, maybe a wrong URL! - throw new Error("Invalid format HTML!"); - } - // check if content is based64 encoded - const Base64 = new Base64Code(); - const keys = ["dm1lc3M", "c3NyOi8v", "dHJvamFu", "c3M6Ly", "c3NkOi8v"]; - if (keys.some(k => raw.indexOf(k) !== -1)) { - output = Base64.safeDecode(raw); - } else { - output = raw; - } - output = output.split("\n"); - for (let i = 0; i < output.length; i++) { - output[i] = output[i].trim(); // trim lines - } - return output.join("\n"); - } - - // Parsers - addParsers( - // URI format parsers - URI_SS, URI_SSR, URI_VMess, URI_Trojan, - // Quantumult X platform - QX_SS, QX_SSR, QX_VMess, QX_Trojan, QX_Http, - // Loon platform - Loon_SS, Loon_SSR, Loon_VMess, Loon_Trojan, Loon_Http, - // Surge platform - Surge_SS, Surge_VMess, Surge_Trojan, Surge_Http - ); - - // Producers - addProducers( - QX_Producer, Loon_Producer, Surge_Producer, Raw_Producer - ); - - return { - parse, produce - }; -} - -function ProxyFilter() { - const filters = []; - - function addFilters(...args) { - args.forEach(a => filters.push(a)); - } - - // select proxies - function process(proxies) { - let selected = FULL(proxies.length, true); - for (const filter of filters) { - try { - selected = AND(selected, filter.func(proxies)); - } catch (err) { - console.log(`Cannot apply filter ${filter.name}\n Reason: ${err}`); - } - } - return proxies.filter((_, i) => selected[i]) - } - - return { - process, addFilters - } -} - -function ProxyOperator() { - const operators = []; - - function addOperators(...args) { - args.forEach(a => operators.push(a)); - } - - // run all operators - function process(proxies) { - let output = clone(proxies); - for (const op of operators) { - try { - const output_ = op.func(output); - if (output_) output = output_; - } catch (err) { - // print log and skip this operator - console.log(`ERROR: cannot apply operator ${op.name}! Reason: ${err}`); - } - } - return output; - } - - return {addOperators, process} -} - -/**************************** URI Format ***************************************/ -// Parse SS URI format (only supports new SIP002, legacy format is depreciated). -// reference: https://shadowsocks.org/en/spec/SIP002-URI-Scheme.html -function URI_SS() { - const patternTest = (line) => { - return /^ss:\/\//.test(line); - } - const Base64 = new Base64Code(); - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - const func = (line) => { - // parse url - let content = line.split("ss://")[1]; - - const proxy = { - name: decodeURIComponent(line.split("#")[1]), - type: "ss", - supported - } - content = content.split("#")[0]; // strip proxy name - - // handle IPV4 and IPV6 - const serverAndPort = content.match(/@([^\/]*)\//)[1]; - const portIdx = serverAndPort.lastIndexOf(":"); - proxy.server = serverAndPort.substring(0, portIdx); - proxy.port = serverAndPort.substring(portIdx + 1); - - const userInfo = Base64.safeDecode(content.split("@")[0]).split(":"); - proxy.cipher = userInfo[0]; - proxy.password = userInfo[1]; - - // handle obfs - const idx = content.indexOf("?plugin="); - if (idx !== -1) { - const pluginInfo = ("plugin=" + decodeURIComponent(content.split("?plugin=")[1])).split(";"); - const params = {}; - for (const item of pluginInfo) { - const [key, val] = item.split("="); - if (key) params[key] = val || true; // some options like "tls" will not have value - } - switch (params.plugin) { - case 'simple-obfs': - proxy.plugin = 'obfs' - proxy['plugin-opts'] = { - mode: params.obfs, - host: params['obfs-host'] - } - break - case 'v2ray-plugin': - proxy.supported = { - ...DEFAULT_SUPPORTED_PLATFORMS, - Loon: false, - Surge: false - } - proxy.obfs = 'v2ray-plugin' - proxy['plugin-opts'] = { - mode: "websocket", - host: params['obfs-host'], - path: params.path || "" - } - break - default: - throw new Error(`Unsupported plugin option: ${params.plugin}`) - } - } - return proxy; - } - return {patternTest, func}; -} - -// Parse URI SSR format, such as ssr://xxx -function URI_SSR() { - const patternTest = (line) => { - return /^ssr:\/\//.test(line); - } - const Base64 = new Base64Code(); - const supported = { - ...DEFAULT_SUPPORTED_PLATFORMS, - Surge: false - } - - const func = (line) => { - line = Base64.safeDecode(line.split("ssr://")[1]); - - // handle IPV6 & IPV4 format - let splitIdx = line.indexOf(':origin'); - if (splitIdx === -1) { - splitIdx = line.indexOf(":auth_"); - } - const serverAndPort = line.substring(0, splitIdx); - const server = serverAndPort.substring(0, serverAndPort.lastIndexOf(":")); - const port = serverAndPort.substring(serverAndPort.lastIndexOf(":") + 1); - - let params = line.substring(splitIdx + 1).split("/?")[0].split(":"); - let proxy = { - type: "ssr", - server, - port, - protocol: params[0], - cipher: params[1], - obfs: params[2], - password: Base64.safeDecode(params[3]), - supported - } - // get other params - params = {}; - line = line.split("/?")[1].split("&"); - if (line.length > 1) { - for (const item of line) { - const [key, val] = item.split("="); - params[key] = val; - } - } - proxy = { - ...proxy, - name: Base64.safeDecode(params.remarks), - "protocol-param": Base64.safeDecode(params.protoparam).replace(/\s/g, "") || "", - "obfs-param": Base64.safeDecode(params.obfsparam).replace(/\s/g, "") || "" - } - return proxy; - } - - return {patternTest, func}; -} - -// V2rayN URI VMess format -// reference: https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2) -function URI_VMess() { - const patternTest = (line) => { - return /^vmess:\/\//.test(line); - } - const Base64 = new Base64Code(); - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - const func = (line) => { - line = line.split("vmess://")[1]; - const params = JSON.parse(Base64.safeDecode(line)); - const proxy = { - name: params.ps, - type: "vmess", - server: params.add, - port: params.port, - cipher: "auto", // V2rayN has no default cipher! use aes-128-gcm as default. - uuid: params.id, - alterId: params.aid || 0, - tls: JSON.parse(params.tls || "false"), - supported - } - // handle obfs - if (params.net === 'ws') { - proxy.network = 'ws'; - proxy['ws-path'] = params.path; - proxy['ws-headers'] = { - Host: params.host || params.add - } - } - return proxy - } - return {patternTest, func}; -} - -// Trojan URI format -function URI_Trojan() { - const patternTest = (line) => { - return /^trojan:\/\//.test(line); - } - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - const func = (line) => { - // trojan forces to use 443 port - if (line.indexOf(":443") === -1) { - throw new Error("Trojan port should always be 443!"); - } - line = line.split("trojan://")[1]; - const server = line.split("@")[1].split(":443")[0]; - - return { - name: `[Trojan] ${server}`, // trojan uri has no server tag! - type: "trojan", - server, - port: 443, - password: line.split("@")[0], - supported - } - } - return {patternTest, func}; -} - -/**************************** Quantumult X ***************************************/ -function QX_SS() { - const patternTest = (line) => { - return /^shadowsocks\s*=/.test(line.split(",")[0].trim()) && line.indexOf("ssr-protocol") === -1; - }; - const func = (line) => { - const params = getQXParams(line); - const proxy = { - name: params.tag, - type: "ss", - server: params.server, - port: params.port, - cipher: params.method, - password: params.password, - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - supported: clone(DEFAULT_SUPPORTED_PLATFORMS) - }; - // handle obfs options - if (params.obfs) { - proxy["plugin-opts"] = { - host: params['obfs-host'] || proxy.server - }; - switch (params.obfs) { - case "http": - case "tls": - proxy.plugin = "obfs"; - proxy["plugin-opts"].mode = params.obfs; - break; - case "ws": - case "wss": - proxy["plugin-opts"] = { - ...proxy["plugin-opts"], - mode: "websocket", - path: params['obfs-uri'], - tls: params.obfs === 'wss' - } - proxy.plugin = "v2ray-plugin" - // Surge and Loon lack support for v2ray-plugin obfs - proxy.supported.Surge = false - proxy.supported.Loon = false - break; - } - } - return proxy; - }; - return {patternTest, func}; -} - -function QX_SSR() { - const patternTest = (line) => { - return /^shadowsocks\s*=/.test(line.split(",")[0].trim()) && line.indexOf("ssr-protocol") !== -1; - }; - const supported = { - ...DEFAULT_SUPPORTED_PLATFORMS, - Surge: false - } - const func = (line) => { - const params = getQXParams(line); - const proxy = { - name: params.tag, - type: "ssr", - server: params.server, - port: params.port, - cipher: params.method, - password: params.password, - protocol: params["ssr-protocol"], - obfs: "plain", // default obfs - "protocol-param": params['ssr-protocol-param'], - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - supported - } - // handle obfs options - if (params.obfs) { - proxy.obfs = params.obfs; - proxy['obfs-param'] = params['obfs-host'] - } - return proxy; - } - return {patternTest, func}; -} - -function QX_VMess() { - const patternTest = (line) => { - return /^vmess\s*=/.test(line.split(",")[0].trim()); - }; - const func = (line) => { - const params = getQXParams(line) - const proxy = { - type: "vmess", - name: params.tag, - server: params.server, - port: params.port, - cipher: params.method || 'none', - uuid: params.password, - alterId: 0, - tls: params.obfs === 'over-tls' || params.obfs === 'wss', - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - } - if (proxy.tls) { - proxy.sni = params['obfs-host'] || params.server; - proxy.scert = !JSON.parse(params['tls-verification'] || 'true'); - } - // handle ws headers - if (params.obfs === 'ws' || params.obfs === 'wss') { - proxy.network = 'ws'; - proxy['ws-path'] = params['obfs-uri']; - proxy['ws-headers'] = { - Host: params['obfs-host'] || params.server // if no host provided, use the same as server - } - } - return proxy; - } - - return {patternTest, func}; -} - -function QX_Trojan() { - const patternTest = (line) => { - return /^trojan\s*=/.test(line.split(",")[0].trim()); - }; - const func = (line) => { - const params = getQXParams(line); - const proxy = { - type: "trojan", - name: params.tag, - server: params.server, - port: params.port, - password: params.password, - sni: params['tls-host'] || params.server, - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - } - proxy.scert = !JSON.parse(params['tls-verification'] || 'true'); - return proxy; - } - return {patternTest, func} -} - -function QX_Http() { - const patternTest = (line) => { - return /^http\s*=/.test(line.split(",")[0].trim()); - }; - const func = (line) => { - const params = getQXParams(line); - const proxy = { - type: "http", - name: params.tag, - server: params.server, - port: params.port, - username: params.username, - password: params.password, - tls: JSON.parse(params['over-tls'] || "false"), - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - } - if (proxy.tls) { - proxy.sni = params['tls-host'] || proxy.server; - proxy.scert = !JSON.parse(params['tls-verification'] || 'true'); - } - return proxy; - } - - return {patternTest, func}; -} - -function getQXParams(line) { - const groups = line.split(","); - const params = {}; - const protocols = ["shadowsocks", "vmess", "http", "trojan"]; - groups.forEach((g) => { - const [key, value] = g.split("="); - if (protocols.indexOf(key) !== -1) { - params.type = key; - const conf = value.split(":"); - params.server = conf[0]; - params.port = conf[1]; - } else { - params[key.trim()] = value.trim(); - } - }); - return params; -} - -/**************************** Loon ***************************************/ -function Loon_SS() { - const patternTest = (line) => { - return line.split(",")[0].split("=")[1].trim().toLowerCase() === 'shadowsocks'; - } - const func = (line) => { - const params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "ss", - server: params[1], - port: params[2], - cipher: params[3], - password: params[4].replace(/"/g, "") - } - // handle obfs - if (params.length > 5) { - proxy.plugin = 'obfs'; - proxy['plugin-opts'] = { - mode: proxy.obfs, - host: params[6] - } - } - return proxy; - } - return {patternTest, func}; -} - -function Loon_SSR() { - const patternTest = (line) => { - return line.split(",")[0].split("=")[1].trim().toLowerCase() === 'shadowsocksr'; - } - const func = (line) => { - const params = line.split("=")[1].split(","); - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - supported.Surge = false; - return { - name: line.split("=")[0].trim(), - type: "ssr", - server: params[1], - port: params[2], - cipher: params[3], - password: params[4].replace(/"/g, ""), - protocol: params[5], - "protocol-param": params[6].match(/{(.*)}/)[1], - supported, - obfs: params[7], - 'obfs-param': params[8].match(/{(.*)}/)[1] - } - } - return {patternTest, func}; -} - -function Loon_VMess() { - const patternTest = (line) => { - // distinguish between surge vmess - return /^.*=\s*vmess/i.test(line.split(",")[0]) && line.indexOf("username") === -1; - } - const func = (line) => { - let params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "vmess", - server: params[1], - port: params[2], - cipher: params[3] || 'none', - uuid: params[4].replace(/"/g, ""), - alterId: 0, - } - // get transport options - params = params.splice(5); - for (const item of params) { - const [key, val] = item.split(":"); - params[key] = val; - } - proxy.tls = JSON.parse(params['over-tls'] || 'false'); - if (proxy.tls) { - proxy.sni = params['tls-name'] || proxy.server; - proxy.scert = JSON.parse(params['skip-cert-verify'] || 'false'); - } - switch (params.transport) { - case "tcp": - break; - case "ws": - proxy.network = params.transport - proxy['ws-path'] = params.path - proxy['ws-headers'] = { - Host: params.host - } - } - if (proxy.tls) { - proxy.scert = JSON.parse(params['skip-cert-verify'] || 'false') - } - return proxy; - } - return {patternTest, func}; -} - -function Loon_Trojan() { - const patternTest = (line) => { - return /^.*=\s*trojan/i.test(line.split(",")[0]) && line.indexOf("password") === -1; - } - - const func = (line) => { - const params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "trojan", - server: params[1], - port: params[2], - password: params[3].replace(/"/g, ""), - sni: params[1], // default sni is the server itself - scert: JSON.parse(params['skip-cert-verify'] || 'false') - } - // trojan sni - if (params.length > 4) { - const [key, val] = params[4].split(":"); - if (key === 'tls-name') proxy.sni = val; - else throw new Error(`ERROR: unknown option ${key} for line: \n${line}`); - } - return proxy; - } - - return {patternTest, func} -} - -function Loon_Http() { - const patternTest = (line) => { - return /^.*=\s*http/i.test(line.split(",")[0]) - && line.split(",").length === 5 - && line.indexOf("username") === -1 - && line.indexOf("password") === -1 - } - - const func = (line) => { - const params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "http", - server: params[1], - port: params[2], - tls: params[2] === "443", // port 443 is considered as https type - username: (params[3] || "").replace(/"/g, ""), - password: (params[4] || "").replace(/"/g, "") - } - if (proxy.tls) { - proxy.sni = params['tls-name'] || proxy.server; - proxy.scert = JSON.parse(params['skip-cert-verify'] || 'false'); - } - - return proxy; - } - return {patternTest, func} -} - -/**************************** Surge ***************************************/ -function Surge_SS() { - const patternTest = (line) => { - return /^.*=\s*ss/.test(line.split(",")[0]); - } - const func = (line) => { - const params = getSurgeParams(line); - const proxy = { - name: params.name, - type: "ss", - server: params.server, - port: params.port, - cipher: params['encrypt-method'], - password: params.password, - tfo: JSON.parse(params.tfo || "false"), - udp: JSON.parse(params['udp-relay'] || "false"), - } - // handle obfs - if (params.obfs) { - proxy.plugin = 'obfs'; - proxy['plugin-opts'] = { - mode: params.obfs, - host: params['obfs-host'] - } - } - return proxy; - } - return {patternTest, func} -} - -function Surge_VMess() { - const patternTest = (line) => { - return /^.*=\s*vmess/.test(line.split(",")[0]) && line.indexOf("username") !== -1; - } - const func = (line) => { - const params = getSurgeParams(line); - const proxy = { - name: params.name, - type: "vmess", - server: params.server, - port: params.port, - uuid: params.username, - alterId: 0, // surge does not have this field - cipher: "none", // surge does not have this field - tls: JSON.parse(params.tls || "false"), - tfo: JSON.parse(params.tfo || "false"), - } - if (proxy.tls) { - proxy.scert = JSON.parse(params['skip-cert-verify'] || "false"); - proxy.sni = params['sni'] || params.server; - } - // use websocket - if (JSON.parse(params.ws || "false")) { - proxy.network = 'ws'; - proxy['ws-path'] = params['ws-path']; - proxy['ws-headers'] = { - Host: params.sni - } - } - return proxy; - } - return {patternTest, func}; -} - -function Surge_Trojan() { - const patternTest = (line) => { - return /^.*=\s*trojan/.test(line.split(",")[0]) && line.indexOf("sni") !== -1; - } - const func = (line) => { - const params = getSurgeParams(line); - return { - name: params.name, - type: "trojan", - server: params.server, - port: params.port, - password: params.password, - sni: params.sni || params.server, - tfo: JSON.parse(params.tfo || "false"), - scert: JSON.parse(params['skip-cert-verify'] || "false"), - } - } - - return {patternTest, func}; -} - -function Surge_Http() { - const patternTest = (line) => { - return /^.*=\s*http/.test(line.split(",")[0]) && !Loon_Http().patternTest(line) - } - const func = (line) => { - const params = getSurgeParams(line); - const proxy = { - name: params.name, - type: "http", - server: params.server, - port: params.port, - tls: JSON.parse(params.tls || "false"), - tfo: JSON.parse(params.tfo || "false"), - } - if (proxy.tls) { - proxy.scert = JSON.parse(params['skip-cert-verify'] || "false"); - proxy.sni = params.sni || params.server; - } - if (params.username !== 'none') proxy.username = params.username; - if (params.password !== 'none') proxy.password = params.password; - return proxy; - } - return {patternTest, func} -} - -function getSurgeParams(line) { - const params = {}; - params.name = line.split("=")[0].trim(); - const segments = line.split(","); - params.server = segments[1].trim(); - params.port = segments[2].trim(); - for (let i = 3; i < segments.length; i++) { - const item = segments[i] - if (item.indexOf("=") !== -1) { - const [key, value] = item.split("="); - params[key.trim()] = value.trim(); - } - } - return params; -} - -/**************************** Output Functions ***************************************/ -function QX_Producer() { - const targetPlatform = "QX"; - const output = (proxy) => { - let obfs_opts; - let tls_opts; - switch (proxy.type) { - case 'ss': - obfs_opts = ""; - if (proxy.plugin === 'obfs') { - obfs_opts = `,obfs=${proxy['plugin-opts'].mode},obfs-host=${proxy['plugin-opts'].host}`; - } - if (proxy.plugin === 'v2ray-plugin') { - const {tls, host, path} = proxy['plugin-opts']; - obfs_opts = `,obfs=${tls ? 'wss' : 'ws'},obfs-host=${host}${path ? ',obfs-uri=' + path : ""}`; - } - return `shadowsocks = ${proxy.server}:${proxy.port}, method=${proxy.cipher}, password=${proxy.password}${obfs_opts}${proxy.tfo ? ", fast-open=true" : ", fast-open=false"}${proxy.udp ? ", udp-relay=true" : ", udp-relay=false"}, tag=${proxy.name}` - case 'ssr': - return `shadowsocks=${proxy.server}:${proxy.port},method=${proxy.cipher},password=${proxy.password},ssr-protocol=${proxy.protocol}${proxy['protocol-param'] ? ",ssr-protocol-param=" + proxy['protocol-param'] : ""}${proxy.obfs ? ",obfs=" + proxy.obfs : ""}${proxy['obfs-param'] ? ",obfs-host=" + proxy['obfs-param'] : ""}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${proxy.udp ? ",udp-relay=true" : ",udp-relay=false"},tag=${proxy.name}` - case 'vmess': - obfs_opts = ""; - if (proxy.network === 'ws') { - // websocket - if (proxy.tls) { - // ws-tls - obfs_opts = `,obfs=wss,obfs-host=${proxy.sni}${proxy['ws-path'] ? ",obfs-uri=" + proxy['ws-path'] : ""},tls-verification=${proxy.scert ? "false" : "true"}`; - } else { - // ws - obfs_opts = `,obfs=ws,obfs-host=${proxy['ws-headers'].Host}${proxy['ws-path'] ? ",obfs-uri=" + proxy['ws-path'] : ""}`; - } - } else { - // tcp - if (proxy.tls) { - obfs_opts = `,obfs=over-tls,obfs-host=${proxy.sni},tls-verification=${proxy.scert ? "false" : "true"}`; - } - } - return `vmess=${proxy.server}:${proxy.port},method=${proxy.cipher},password=${proxy.uuid}${obfs_opts}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${proxy.udp ? ",udp-relay=true" : ",udp-relay=false"},tag=${proxy.name}` - case 'trojan': - return `trojan=${proxy.server}:${proxy.port},password=${proxy.password},tls-host=${proxy.sni},tls-verification=${proxy.scert ? "false" : "true"}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${proxy.udp ? ",udp-relay=true" : ",udp-relay=false"},tag=${proxy.name}` - case 'http': - tls_opts = ""; - if (proxy.tls) { - tls_opts = `,over-tls=true,tls-verification=${proxy.scert ? "false" : "true"},tls-host=${proxy.sni}`; - } - return `http=${proxy.server}:${proxy.port},username=${proxy.username},password=${proxy.password}${tls_opts}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"},tag=${proxy.name}`; - } - throw new Error(`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`); - } - return {targetPlatform, output}; -} - -function Loon_Producer() { - const targetPlatform = "Loon"; - const output = (proxy) => { - let obfs_opts, tls_opts; - switch (proxy.type) { - case "ss": - obfs_opts = ",,"; - if (proxy.plugin === 'obfs') { - const {mode, host} = proxy['plugin-opts']; - obfs_opts = `,${mode},${host}` - } - return `${proxy.name}=shadowsocks,${proxy.server},${proxy.port},${proxy.cipher},${proxy.password}${obfs_opts}`; - case "ssr": - return `${proxy.name}=shadowsocksr,${proxy.server},${proxy.port},${proxy.cipher},${proxy.password},${proxy.protocol},{${proxy['protocol-param']}},${proxy.obfs},{${proxy['obfs-param']}}` - case "vmess": - obfs_opts = ""; - if (proxy.network === 'ws') { - const host = proxy['ws-headers'].Host; - obfs_opts = `,transport:ws,host:${host},path:${proxy['ws-path']}`; - } else { - obfs_opts = `,transport:tcp`; - } - if (proxy.tls) { - obfs_opts += `,tls-name=${proxy.sni},skip-cert-verify:${proxy.scert}`; - } - return `${proxy.name}=vmess,${proxy.server},${proxy.port},${proxy.cipher},over-tls:${proxy.tls}${obfs_opts}`; - case "trojan": - return `${proxy.name}=trojan,${proxy.server},${proxy.port},${proxy.password},tls-name:${proxy.sni},skip-cert-verify:${proxy.scert}`; - case "http": - tls_opts = ""; - const base = `${proxy.name}=${proxy.tls ? 'http' : 'https'},${proxy.server},${proxy.port},${proxy.username || ""},${proxy.password || ""}`; - if (proxy.tls) { - // https - tls_opts = `,skip-cert-verify:${proxy.scert},tls-name:${proxy.sni}`; - return base + tls_opts; - } else return base; - } - throw new Error(`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`); - } - return {targetPlatform, output} -} - -function Surge_Producer() { - const targetPlatform = "Surge"; - const output = (proxy) => { - let obfs_opts, tls_opts; - switch (proxy.type) { - case 'ss': - obfs_opts = ""; - if (proxy.plugin === "obfs") { - obfs_opts = `,obfs=${proxy['plugin-opts'].mode},obfs-host=${proxy['plugin-opts'].host}` - } else { - throw new Error(`Platform ${targetPlatform} does not support obfs option: ${proxy.obfs}`); - } - return `${proxy.name}=ss,${proxy.server},${proxy.port},encrypt-method=${proxy.cipher},password=${proxy.password}${obfs_opts},tfo=${proxy.tfo || 'false'},udp-relay=${proxy.udp || 'false'}`; - case 'vmess': - tls_opts = ""; - let config = `${proxy.name}=vmess,${proxy.server},${proxy.port},username=${proxy.uuid},tls=${proxy.tls},tfo=${proxy.tfo || "false"}`; - if (proxy.network === 'ws') { - const path = proxy['ws-path']; - const host = proxy['ws-headers'].Host; - config += `,ws=true${path ? ',ws-path=' + path : ""}${host ? ',ws-headers=HOST:' + host : ""}`; - } - if (proxy.tls) { - config += `,skip-cert-verify=${proxy.scert},sni=${proxy.sni}`; - } - return config; - case 'trojan': - return `${proxy.name}=trojan,${proxy.server},${proxy.port},password=${proxy.password},sni=${proxy.sni},tfo=${proxy.tfo || 'false'}`; - case 'http': - tls_opts = ",tls=false"; - if (proxy.tls) { - tls_opts = `,tls=true,skip-cert-verify=${proxy.scert},sni=${proxy.sni}`; - } - return `${proxy.name}=http,${proxy.server},${proxy.port}${proxy.username ? ",username=" + proxy.username : ""}${proxy.password ? ",password=" + proxy.password : ""}${tls_opts},tfo=${proxy.tfo || 'false'}`; - } - throw new Error(`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`); - } - return {targetPlatform, output}; -} - -function Raw_Producer() { - const targetPlatform = "Raw"; - const output = (proxy) => { - return JSON.stringify(proxy); - } - return {targetPlatform, output}; -} - -/**************************** Operators ***************************************/ -// force to set some properties (e.g., scert, udp, tfo, etc.) -function SetPropertyOperator(key, val) { - return { - name: "Set Property Operator", - func: proxies => { - return proxies.map(p => { - p[key] = val; - return p; - }) - } - } -} - -// add or remove flag for proxies -function FlagOperator(type) { - return { - name: "Flag Operator", - func: proxies => { - return proxies.map(proxy => { - switch (type) { - case 0: - // no flag - proxy.name = removeFlag(proxy.name); - break - case 1: - // get flag - const newFlag = getFlag(proxy.name); - // remove old flag - proxy.name = removeFlag(proxy.name); - proxy.name = newFlag + " " + proxy.name; - proxy.name = proxy.name.replace(/🇹🇼/g, "🇨🇳"); - break; - default: - throw new Error("Unknown flag type: " + type); - } - return proxy; - }) - } - } -} - -// sort proxies according to their names -function SortOperator(order = 'asc') { - return { - name: "Sort Operator", - func: proxies => { - switch (order) { - case "asc": - case 'desc': - return proxies.sort((a, b) => { - let res = (a.name > b.name) ? 1 : -1; - res *= order === 'desc' ? -1 : 1; - return res - }) - case 'random': - return shuffle(proxies); - default: - throw new Error("Unknown sort option: " + order); - } - } - } -} - -// sort by keywords -function KeywordSortOperator(...keywords) { - return { - name: "Keyword Sort Operator", - func: proxies => proxies.sort((a, b) => { - const oA = getKeywordOrder(keywords, a.name); - const oB = getKeywordOrder(keywords, b.name); - if (oA && !oB) return -1; - if (oB && !oA) return 1; - if (oA && oB) return oA < oB ? -1 : 1; - if ((!oA && !oB) || (oA && oB && oA === oB)) return a.name < b.name ? -1 : 1; // fallback to normal sort - }) - } -} - -function getKeywordOrder(keywords, str) { - let order = null; - for (let i = 0; i < keywords.length; i++) { - if (str.indexOf(keywords[i]) !== -1) { - order = i + 1; // plus 1 is important! 0 will be treated as false!!! - break; - } - } - return order; -} - -// rename by keywords -// keywords: [{old: "old", now: "now"}] -function KeywordRenameOperator(...keywords) { - return { - name: "Keyword Rename Operator", - func: proxies => { - return proxies.map(proxy => { - for (const {old, now} of keywords) { - proxy.name = proxy.name.replace(old, now); - } - return proxy; - }) - } - } -} - -// rename by regex -// keywords: [{expr: "string format regex", now: "now"}] -function RegexRenameOperator(...regex) { - return { - name: "Regex Rename Operator", - func: proxies => { - return proxies.map(proxy => { - for (const {expr, now} of regex) { - proxy.name = proxy.name.replace(new RegExp(expr, "g"), now); - } - return proxy; - }) - } - } -} - -// delete keywords operator -// keywords: ['a', 'b', 'c'] -function KeywordDeleteOperator(...keywords) { - const keywords_ = keywords.map(k => { - return { - old: k, - now: "" - } - }) - return { - name: "Keyword Delete Operator", - func: KeywordRenameOperator(keywords_).func - } -} - -// delete regex operator -// regex: ['a', 'b', 'c'] -function RegexDeleteOperator(...regex) { - const regex_ = regex.map(r => { - return { - expr: r, - now: "" - } - }); - return { - name: "Regex Delete Operator", - func: RegexRenameOperator(regex_).func - } -} - -// use base64 encoded script to rename -/** Example script - function func(proxies) { - // do something - return proxies; - } - - WARNING: - 1. This function name should be `func`! - 2. Always declare variable before using it! - */ -function ScriptOperator(script) { - return { - name: "Script Operator", - func: (proxies) => { - ;(function () { - eval(script); - return func(proxies); - })(); - } - } -} - -/**************************** Filters ***************************************/ -// filter by keywords -function KeywordFilter(...keywords) { - return { - name: "Keyword Filter", - func: (proxies) => { - return proxies.map(proxy => keywords.some(k => proxy.name.indexOf(k) !== -1)); - } - } -} - -function DiscardKeywordFilter(...keywords) { - return { - name: "Discard Keyword Filter", - func: proxies => { - const filter = KeywordFilter(keywords).func; - return NOT(filter(proxies)); - } - } -} - -// filter useless proxies -function UselessFilter() { - const KEYWORDS = ["流量", "时间", "应急", "过期", "Bandwidth", "expire"]; - return { - name: "Useless Filter", - func: DiscardKeywordFilter(KEYWORDS).func - } -} - -// filter by regions -function RegionFilter(...regions) { - const REGION_MAP = { - "HK": "🇭🇰", - "TW": "🇹🇼", - "US": "🇺🇸", - "SG": "🇸🇬", - "JP": "🇯🇵", - "UK": "🇬🇧", - "KR": "🇰🇷" - }; - return { - name: "Region Filter", - func: (proxies) => { - // this would be high memory usage - return proxies.map(proxy => { - const flag = getFlag(proxy.name); - return regions.some(r => REGION_MAP[r] === flag); - }) - } - } -} - -// filter by regex -function RegexFilter(...regex) { - return { - name: "Regex Filter", - func: (proxies) => { - return proxies.map(proxy => regex.some(r => r.test(proxy.name))); - } - } -} - -function DiscardRegexFilter(...regex) { - return { - name: "Discard Regex Filter", - func: proxies => { - const filter = RegexFilter(regex).func; - return NOT(filter(proxies)); - } - } -} - -// filter by proxy types -function TypeFilter(...types) { - return { - name: "Type Filter", - func: (proxies) => { - return proxies.map(proxy => types.some(t => proxy.type === t)); - } - } -} - -// use base64 encoded script to filter proxies -/** Script Example - function func(proxies) { - const selected = FULL(proxies.length, true); - // do something - return selected; - } - WARNING: - 1. This function name should be `func`! - 2. Always declare variable before using it! - */ -function ScriptFilter(script) { - return { - name: "Script Filter", - func: (proxies) => { - !(function () { - eval(script); - return filter(proxies); - })(); - } - } -} - -/******************************** Utility Functions *********************************************/ -// get proxy flag according to its name -function getFlag(name) { - // flags from @KOP-XIAO: https://github.com/KOP-XIAO/QuantumultX/blob/master/Scripts/resource-parser.js - const flags = { - "🏳️‍🌈": ["流量", "时间", "应急", "过期", "Bandwidth", "expire"], - "🇦🇨": ["AC"], - "🇦🇹": ["奥地利", "维也纳"], - "🇦🇺": ["AU", "Australia", "Sydney", "澳大利亚", "澳洲", "墨尔本", "悉尼"], - "🇧🇪": ["BE", "比利时"], - "🇧🇬": ["保加利亚", "Bulgaria"], - "🇧🇷": ["BR", "Brazil", "巴西", "圣保罗"], - "🇨🇦": ["Canada", "Waterloo", "加拿大", "蒙特利尔", "温哥华", "楓葉", "枫叶", "滑铁卢", "多伦多"], - "🇨🇭": ["瑞士", "苏黎世", "Switzerland"], - "🇩🇪": ["DE", "German", "GERMAN", "德国", "德國", "法兰克福"], - "🇩🇰": ["丹麦"], - "🇪🇸": ["ES", "西班牙", "Spain"], - "🇪🇺": ["EU", "欧盟", "欧罗巴"], - "🇫🇮": ["Finland", "芬兰", "赫尔辛基"], - "🇫🇷": ["FR", "France", "法国", "法國", "巴黎"], - "🇬🇧": ["UK", "GB", "England", "United Kingdom", "英国", "伦敦", "英"], - "🇲🇴": ["MO", "Macao", "澳门", "CTM"], - "🇭🇺": ["匈牙利", "Hungary"], - "🇭🇰": ["HK", "Hongkong", "Hong Kong", "香港", "深港", "沪港", "呼港", "HKT", "HKBN", "HGC", "WTT", "CMI", "穗港", "京港", "港"], - "🇮🇩": ["Indonesia", "印尼", "印度尼西亚", "雅加达"], - "🇮🇪": ["Ireland", "爱尔兰", "都柏林"], - "🇮🇳": ["India", "印度", "孟买", "Mumbai"], - "🇰🇵": ["KP", "朝鲜"], - "🇰🇷": ["KR", "Korea", "KOR", "韩国", "首尔", "韩", "韓"], - "🇱🇻": ["Latvia", "Latvija", "拉脱维亚"], - "🇲🇽️": ["MEX", "MX", "墨西哥"], - "🇲🇾": ["MY", "Malaysia", "马来西亚", "吉隆坡"], - "🇳🇱": ["NL", "Netherlands", "荷兰", "荷蘭", "尼德蘭", "阿姆斯特丹"], - "🇵🇭": ["PH", "Philippines", "菲律宾"], - "🇷🇴": ["RO", "罗马尼亚"], - "🇷🇺": ["RU", "Russia", "俄罗斯", "俄羅斯", "伯力", "莫斯科", "圣彼得堡", "西伯利亚", "新西伯利亚", "京俄", "杭俄"], - "🇸🇦": ["沙特", "迪拜"], - "🇸🇪": ["SE", "Sweden"], - "🇸🇬": ["SG", "Singapore", "新加坡", "狮城", "沪新", "京新", "泉新", "穗新", "深新", "杭新", "广新"], - "🇹🇭": ["TH", "Thailand", "泰国", "泰國", "曼谷"], - "🇹🇷": ["TR", "Turkey", "土耳其", "伊斯坦布尔"], - "🇹🇼": ["TW", "Taiwan", "台湾", "台北", "台中", "新北", "彰化", "CHT", "台", "HINET"], - "🇺🇸": ["US", "USA", "America", "United States", "美国", "美", "京美", "波特兰", "达拉斯", "俄勒冈", "凤凰城", "费利蒙", "硅谷", "矽谷", "拉斯维加斯", "洛杉矶", "圣何塞", "圣克拉拉", "西雅图", "芝加哥", "沪美", "哥伦布", "纽约"], - "🇻🇳": ["VN", "越南", "胡志明市"], - "🇮🇹": ["Italy", "IT", "Nachash", "意大利", "米兰", "義大利"], - "🇿🇦": ["South Africa", "南非"], - "🇦🇪": ["United Arab Emirates", "阿联酋"], - "🇯🇵": ["JP", "Japan", "日", "日本", "东京", "大阪", "埼玉", "沪日", "穗日", "川日", "中日", "泉日", "杭日", "深日", "辽日", "广日"], - "🇦🇷": ["AR", "阿根廷"], - "🇳🇴": ["Norway", "挪威", "NO"], - "🇨🇳": ["CN", "China", "回国", "中国", "江苏", "北京", "上海", "广州", "深圳", "杭州", "徐州", "青岛", "宁波", "镇江", "back"] - }; - for (let k of Object.keys(flags)) { - if (flags[k].some((item => name.indexOf(item) !== -1))) { - return k; - } - } - // no flag found - const oldFlag = (name.match(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/) || [])[0]; - return oldFlag || "🏴‍☠️"; -} - -// remove flag -function removeFlag(str) { - return str.replace(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/g, "").trim(); -} - -// clone an object -function clone(obj) { - return JSON.parse(JSON.stringify(obj)) -} - -// shuffle array -function shuffle(array) { - let currentIndex = array.length, temporaryValue, randomIndex; - - // While there remain elements to shuffle... - while (0 !== currentIndex) { - - // Pick a remaining element... - randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex -= 1; - - // And swap it with the current element. - temporaryValue = array[currentIndex]; - array[currentIndex] = array[randomIndex]; - array[randomIndex] = temporaryValue; - } - - return array; -} - -// some logical functions for proxy filters -function AND(...args) { - return args.reduce((a, b) => a.map((c, i) => b[i] && c)); -} - -function OR(...args) { - return args.reduce((a, b) => a.map((c, i) => b[i] || c)) -} - -function NOT(array) { - return array.map(c => !c); -} - -function FULL(length, bool) { - return [...Array(length).keys()].map(() => bool); -} - -// UUID -// source: https://stackoverflow.com/questions/105034/how-to-create-guid-uuid -function UUID() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); -} - -// get platform form UA -function getPlatformFromHeaders(headers) { - const keys = Object.keys(headers); - let UA = ""; - for (let k of keys) { - if (k.match(/USER-AGENT/i)) { - UA = headers[k]; - break; - } - } - if (UA.indexOf("Quantumult%20X") !== -1) { - return "QX"; - } else if (UA.indexOf("Surge") !== -1) { - return "Surge"; - } else if (UA.indexOf("Decar") !== -1) { - return "Loon"; - } else { - // browser - return FALL_BACK_TARGET; - } -} - -/*********************************** OpenAPI *************************************/ -// OpenAPI -// prettier-ignore -function ENV() { - const isQX = typeof $task != "undefined"; - const isLoon = typeof $loon != "undefined"; - const isSurge = typeof $httpClient != "undefined" && !this.isLoon; - const isJSBox = typeof require == "function" && typeof $jsbox != "undefined"; - const isNode = typeof require == "function" && !isJSBox; - const isRequest = typeof $request !== "undefined"; - return {isQX, isLoon, isSurge, isNode, isJSBox, isRequest}; -} - -function HTTP(baseURL, defaultOptions = {}) { - const {isQX, isLoon, isSurge} = ENV(); - const methods = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"]; - - function send(method, options) { - options = typeof options === "string" ? {url: options} : options; - options.url = baseURL ? baseURL + options.url : options.url; - options = {...defaultOptions, ...options}; - const timeout = options.timeout; - const events = { - ...{ - onRequest: () => { - }, - onResponse: (resp) => resp, - onTimeout: () => { - }, - }, - ...options.events, - }; - - events.onRequest(method, options); - - let worker; - if (isQX) { - worker = $task.fetch({method, ...options}); - } else { - worker = new Promise((resolve, reject) => { - const request = isSurge || isLoon ? $httpClient : require("request"); - request[method.toLowerCase()](options, (err, response, body) => { - if (err) reject(err); - else - resolve({ - statusCode: response.status || response.statusCode, - headers: response.headers, - body, - }); - }); - }); - } - - let timeoutid; - const timer = timeout - ? new Promise((_, reject) => { - timeoutid = setTimeout(() => { - events.onTimeout(); - return reject( - `${method} URL: ${options.url} exceeds the timeout ${timeout} ms` - ); - }, timeout); - }) - : null; - - return (timer - ? Promise.race([timer, worker]).then((res) => { - clearTimeout(timeoutid); - return res; - }) - : worker - ) - .then((resp) => events.onResponse(resp)) - } - - const http = {}; - methods.forEach( - (method) => - (http[method.toLowerCase()] = (options) => send(method, options)) - ); - return http; -} - -function API(name = "untitled", debug = false) { - const {isQX, isLoon, isSurge, isNode, isJSBox} = ENV(); - return new (class { - constructor(name, debug) { - this.name = name; - this.debug = debug; - - this.http = HTTP(); - this.env = ENV(); - - this.node = (() => { - if (isNode) { - const fs = require("fs"); - - return { - fs, - }; - } else { - return null; - } - })(); - this.initCache(); - - const delay = (t, v) => - new Promise(function (resolve) { - setTimeout(resolve.bind(null, v), t); - }); - - Promise.prototype.delay = function (t) { - return this.then(function (v) { - return delay(t, v); - }); - }; - } - - // persistance - - // initialize cache - initCache() { - if (isQX) this.cache = JSON.parse($prefs.valueForKey(this.name) || "{}"); - if (isLoon || isSurge) - this.cache = JSON.parse($persistentStore.read(this.name) || "{}"); - - if (isNode) { - // create a json for root cache - let fpath = "root.json"; - if (!this.node.fs.existsSync(fpath)) { - this.node.fs.writeFileSync( - fpath, - JSON.stringify({}), - {flag: "wx"}, - (err) => console.log(err) - ); - } - this.root = {}; - - // create a json file with the given name if not exists - fpath = `${this.name}.json`; - if (!this.node.fs.existsSync(fpath)) { - this.node.fs.writeFileSync( - fpath, - JSON.stringify({}), - {flag: "wx"}, - (err) => console.log(err) - ); - this.cache = {}; - } else { - this.cache = JSON.parse( - this.node.fs.readFileSync(`${this.name}.json`) - ); - } - } - } - - // store cache - persistCache() { - const data = JSON.stringify(this.cache); - if (isQX) $prefs.setValueForKey(data, this.name); - if (isLoon || isSurge) $persistentStore.write(data, this.name); - if (isNode) { - this.node.fs.writeFileSync( - `${this.name}.json`, - data, - {flag: "w"}, - (err) => console.log(err) - ); - this.node.fs.writeFileSync( - "root.json", - JSON.stringify(this.root), - {flag: "w"}, - (err) => console.log(err) - ); - } - } - - write(data, key) { - this.log(`SET ${key}`); - if (key.indexOf("#") !== -1) { - key = key.substr(1); - if (isSurge & isLoon) { - $persistentStore.write(data, key); - } - if (isQX) { - $prefs.setValueForKey(data, key); - } - if (isNode) { - this.root[key] = data; - } - } else { - this.cache[key] = data; - } - this.persistCache(); - } - - read(key) { - this.log(`READ ${key}`); - if (key.indexOf("#") !== -1) { - key = key.substr(1); - if (isSurge & isLoon) { - return $persistentStore.read(key); - } - if (isQX) { - return $prefs.valueForKey(key); - } - if (isNode) { - return this.root[key]; - } - } else { - return this.cache[key]; - } - } - - delete(key) { - this.log(`DELETE ${key}`); - if (key.indexOf("#") !== -1) { - key = key.substr(1); - if (isSurge & isLoon) { - $persistentStore.write(null, key); - } - if (isQX) { - $prefs.removeValueForKey(key); - } - if (isNode) { - delete this.root[key]; - } - } else { - delete this.cache[key]; - } - this.persistCache(); - } - - // notification - notify(title, subtitle = "", content = "", options = {}) { - const openURL = options["open-url"]; - const mediaURL = options["media-url"]; - - const content_ = - content + - (openURL ? `\n点击跳转: ${openURL}` : "") + - (mediaURL ? `\n多媒体: ${mediaURL}` : ""); - - if (isQX) $notify(title, subtitle, content, options); - if (isSurge) $notification.post(title, subtitle, content_); - if (isLoon) $notification.post(title, subtitle, content, openURL); - if (isNode) { - if (isJSBox) { - const push = require("push"); - push.schedule({ - title: title, - body: (subtitle ? subtitle + "\n" : "") + content_, - }); - } else { - console.log(`${title}\n${subtitle}\n${content_}\n\n`); - } - } - } - - // other helper functions - log(msg) { - if (this.debug) console.log(msg); - } - - info(msg) { - console.log(msg); - } - - error(msg) { - console.log("ERROR: " + msg); - } - - wait(millisec) { - return new Promise((resolve) => setTimeout(resolve, millisec)); - } - - done(value = {}) { - if (isQX || isLoon || isSurge) { - $done(value); - } else if (isNode && !isJSBox) { - if (typeof $context !== "undefined") { - $context.headers = value.headers; - $context.statusCode = value.statusCode; - $context.body = value.body; - } - } - } - })(name, debug); -} - -/*********************************** Mini Express *************************************/ -function express(port = 3000) { - const {isNode} = ENV(); - - // node support - if (isNode) { - const express_ = require("express"); - const bodyParser = require("body-parser"); - const app = express_(); - app.use(bodyParser.json({verify: rawBodySaver})); - app.use(bodyParser.urlencoded({verify: rawBodySaver, extended: true})); - app.use(bodyParser.raw({verify: rawBodySaver, type: '*/*'})); - - // adapter - app.start = () => { - app.listen(port, () => { - console.log(`Express started on port: ${port}`); - }) - } - return app; - } - - // route handlers - const handlers = []; - - // http methods - const METHODS_NAMES = [ - "GET", - "POST", - "PUT", - "DELETE", - "PATCH", - "OPTIONS", - "HEAD'", - "ALL", - ]; - - // dispatch url to route - const dispatch = (request, start = 0) => { - let {method, url, headers, body} = request; - method = method.toUpperCase(); - const {path, query} = extractURL(url); - let handler = null; - let i; - - for (i = start; i < handlers.length; i++) { - if (handlers[i].method === "ALL" || method === handlers[i].method) { - const {pattern} = handlers[i]; - if (patternMatched(pattern, path)) { - handler = handlers[i]; - break; - } - } - } - if (handler) { - // dispatch to next handler - const next = () => { - dispatch(method, url, i); - }; - const req = { - method, url, path, query, - params: extractPathParams(handler.pattern, path), - headers, body - }; - const res = Response(); - handler.callback(req, res, next).catch(err => { - res.status(500).json({ - status: "failed", - message: err - }); - }); - } else { - // no route, return 404 - const res = Response(); - res.status("404").json({ - status: "failed", - message: "ERROR: 404 not found" - }); - } - }; - - const app = {}; - - // attach http methods - METHODS_NAMES.forEach((method) => { - app[method.toLowerCase()] = (pattern, callback) => { - // add handler - handlers.push({method, pattern, callback}); - }; - }); - - // chainable route - app.route = (pattern) => { - const chainApp = {}; - METHODS_NAMES.forEach((method) => { - chainApp[method.toLowerCase()] = (callback) => { - // add handler - handlers.push({method, pattern, callback}); - return chainApp; - }; - }); - return chainApp; - }; - - // start service - app.start = () => { - dispatch($request); - }; - - return app; - - /************************************************ - Utility Functions - *************************************************/ - function rawBodySaver(req, res, buf, encoding) { - if (buf && buf.length) { - req.rawBody = buf.toString(encoding || 'utf8'); - } - } - - function Response() { - let statusCode = "200"; - const {isQX, isLoon, isSurge} = ENV(); - const headers = { - "Content-Type": "text/plain;charset=UTF-8", - }; - return new (class { - status(code) { - statusCode = code; - return this; - } - - send(body = "") { - const response = { - status: statusCode, - body, - headers, - }; - if (isQX) { - $done(...response); - } else if (isLoon || isSurge) { - $done({ - response, - }); - } - } - - end() { - this.send(); - } - - html(data) { - this.set("Content-Type", "text/html;charset=UTF-8"); - this.send(data); - } - - json(data) { - this.set("Content-Type", "application/json;charset=UTF-8"); - this.send(JSON.stringify(data)); - } - - set(key, val) { - headers[key] = val; - return this; - } - })(); - } - - function patternMatched(pattern, path) { - if (pattern instanceof RegExp && pattern.test(path)) { - return true; - } else { - // root pattern, match all - if (pattern === "/") return true; - // normal string pattern - if (pattern.indexOf(":") === -1) { - const spath = path.split("/"); - const spattern = pattern.split("/"); - for (let i = 0; i < spattern.length; i++) { - if (spath[i] !== spattern[i]) { - return false; - } - } - return true; - } - // string pattern with path parameters - else if (extractPathParams(pattern, path)) { - return true; - } - } - return false; - } - - function extractURL(url) { - // extract path - const match = url.match(/https?:\/\/[^\/]+(\/[^?]*)/) || []; - const path = match[1] || "/"; - - // extract query string - const split = url.indexOf("?"); - const query = {}; - if (split !== -1) { - let hashes = url.slice(url.indexOf("?") + 1).split("&"); - for (let i = 0; i < hashes.length; i++) { - hash = hashes[i].split("="); - query[hash[0]] = hash[1]; - } - } - return { - path, - query, - }; - } - - function extractPathParams(pattern, path) { - if (pattern.indexOf(":") === -1) { - return null; - } else { - const params = {}; - for (let i = 0, j = 0; i < pattern.length; i++, j++) { - if (pattern[i] === ":") { - let key = []; - let val = []; - while (pattern[++i] !== "/" && i < pattern.length) { - key.push(pattern[i]); - } - while (path[j] !== "/" && j < path.length) { - val.push(path[j++]); - } - params[key.join("")] = val.join(""); - } else { - if (pattern[i] !== path[j]) { - return null; - } - } - } - return params; - } - } -} - -/******************************** Base 64 *********************************************/ -// Base64 Coding Library -// https://github.com/dankogai/js-base64#readme -// Under BSD License -function Base64Code() { - // constants - const b64chars - = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - const b64tab = function (bin) { - const t = {}; - let i = 0; - const l = bin.length; - for (; i < l; i++) t[bin.charAt(i)] = i; - return t; - }(b64chars); - const fromCharCode = String.fromCharCode; - // encoder stuff - const cb_utob = function (c) { - let cc; - if (c.length < 2) { - cc = c.charCodeAt(0); - return cc < 0x80 ? c - : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) - + fromCharCode(0x80 | (cc & 0x3f))) - : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | (cc & 0x3f))); - } else { - cc = 0x10000 - + (c.charCodeAt(0) - 0xD800) * 0x400 - + (c.charCodeAt(1) - 0xDC00); - return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) - + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | (cc & 0x3f))); - } - }; - const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; - const utob = function (u) { - return u.replace(re_utob, cb_utob); - }; - const cb_encode = function (ccc) { - const padlen = [0, 2, 1][ccc.length % 3], - ord = ccc.charCodeAt(0) << 16 - | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) - | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), - chars = [ - b64chars.charAt(ord >>> 18), - b64chars.charAt((ord >>> 12) & 63), - padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), - padlen >= 1 ? '=' : b64chars.charAt(ord & 63) - ]; - return chars.join(''); - }; - const btoa = function (b) { - return b.replace(/[\s\S]{1,3}/g, cb_encode); - }; - this.encode = function (u) { - const isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]'; - return isUint8Array ? u.toString('base64') - : btoa(utob(String(u))); - } - const uriencode = function (u, urisafe) { - return !urisafe - ? _encode(u) - : _encode(String(u)).replace(/[+\/]/g, function (m0) { - return m0 === '+' ? '-' : '_'; - }).replace(/=/g, ''); - }; - const encodeURI = function (u) { - return uriencode(u, true) - }; - // decoder stuff - const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; - const cb_btou = function (cccc) { - switch (cccc.length) { - case 4: - const cp = ((0x07 & cccc.charCodeAt(0)) << 18) - | ((0x3f & cccc.charCodeAt(1)) << 12) - | ((0x3f & cccc.charCodeAt(2)) << 6) - | (0x3f & cccc.charCodeAt(3)), - offset = cp - 0x10000; - return (fromCharCode((offset >>> 10) + 0xD800) - + fromCharCode((offset & 0x3FF) + 0xDC00)); - case 3: - return fromCharCode( - ((0x0f & cccc.charCodeAt(0)) << 12) - | ((0x3f & cccc.charCodeAt(1)) << 6) - | (0x3f & cccc.charCodeAt(2)) - ); - default: - return fromCharCode( - ((0x1f & cccc.charCodeAt(0)) << 6) - | (0x3f & cccc.charCodeAt(1)) - ); - } - }; - const btou = function (b) { - return b.replace(re_btou, cb_btou); - }; - const cb_decode = function (cccc) { - const len = cccc.length, - padlen = len % 4, - n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) - | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) - | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) - | (len > 3 ? b64tab[cccc.charAt(3)] : 0), - chars = [ - fromCharCode(n >>> 16), - fromCharCode((n >>> 8) & 0xff), - fromCharCode(n & 0xff) - ]; - chars.length -= [0, 0, 2, 1][padlen]; - return chars.join(''); - }; - const _atob = function (a) { - return a.replace(/\S{1,4}/g, cb_decode); - }; - const atob = function (a) { - return _atob(String(a).replace(/[^A-Za-z0-9\+\/]/g, '')); - }; - const _decode = function (u) { - return btou(_atob(u)) - }; - this.decode = function (a) { - return _decode( - String(a).replace(/[-_]/g, function (m0) { - return m0 === '-' ? '+' : '/' - }) - .replace(/[^A-Za-z0-9\+\/]/g, '') - ).replace(/>/g, ">").replace(/</g, "<"); - }; - this.safeEncode = function (a) { - return this.encode(a.replace(/\+/g, "-").replace(/\//g, "_")); - } - this.safeDecode = function (a) { - return this.decode(a.replace(/-/g, "+").replace(/_/g, "/")); - } -} \ No newline at end of file diff --git a/collection.json b/collection.json deleted file mode 100644 index 2c32851c7d..0000000000 --- a/collection.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Surge", - "subscriptions": ["AAEX", "Nexitally"] -} \ No newline at end of file diff --git a/config/Egern.yaml b/config/Egern.yaml new file mode 100644 index 0000000000..83a99b5fe0 --- /dev/null +++ b/config/Egern.yaml @@ -0,0 +1,38 @@ +name: Sub-Store +description: '支持 Surge 正式版的参数设置功能. 测落地功能 ability: http-client-policy, 同步配置的定时 cronexp: 55 23 * * *' +compat_arguments: + ability: http-client-policy + cronexp: 55 23 * * * + sync: '"Sub-Store Sync"' + timeout: '120' + engine: auto + produce: '"# Sub-Store Produce"' + produce_cronexp: 50 */6 * * * + produce_sub: '"sub1,sub2"' + produce_col: '"col1,col2"' +compat_arguments_desc: '\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 ''同步'' 或 ''同步配置''\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅' +scriptings: +- http_request: + name: Sub-Store Core + match: ^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))) + script_url: https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js + body_required: true +- http_request: + name: Sub-Store Simple + match: ^https?:\/\/sub\.store + script_url: https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js + body_required: true +- schedule: + name: '{{{sync}}}' + cron: '{{{cronexp}}}' + script_url: https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js +- schedule: + name: '{{{produce}}}' + cron: '{{{produce_cronexp}}}' + script_url: https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js + arguments: + _compat.$argument: '"sub={{{produce_sub}}}&col={{{produce_col}}}"' +mitm: + hostnames: + includes: + - sub.store diff --git a/config/Loon.plugin b/config/Loon.plugin new file mode 100644 index 0000000000..7ccf8d7183 --- /dev/null +++ b/config/Loon.plugin @@ -0,0 +1,20 @@ +#!name=Sub-Store +#!desc=高级订阅管理工具. 定时任务默认为每天 23 点 55 分. 定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置' +#!openUrl=https://sub.store +#!author=Peng-YM +#!homepage=https://github.com/sub-store-org/Sub-Store +#!icon=https://raw.githubusercontent.com/58xinian/icon/master/Sub-Store1.png +#!select = 节点缓存有效期,1分钟,5分钟,10分钟,30分钟,1小时,2小时,3小时,6小时,12小时,24小时,48小时,72小时,参数传入 +#!select = 响应头缓存有效期,1分钟,5分钟,10分钟,30分钟,1小时,2小时,3小时,6小时,12小时,24小时,48小时,72小时,参数传入 + +[Rule] +DOMAIN,sub-store.vercel.app,PROXY + +[MITM] +hostname=sub.store + +[Script] +http-request ^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))) script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js, requires-body=true, timeout=120, tag=Sub-Store Core +http-request ^https?:\/\/sub\.store script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js, requires-body=true, timeout=120, tag=Sub-Store Simple + +cron "55 23 * * *" script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js, timeout=120, tag=Sub-Store Sync \ No newline at end of file diff --git a/config/QX-Task.json b/config/QX-Task.json new file mode 100644 index 0000000000..07377cfae6 --- /dev/null +++ b/config/QX-Task.json @@ -0,0 +1,7 @@ +{ + "name": "Sub-Store", + "description": "定时任务默认为每天 23 点 55 分. 定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置'", + "task": [ + "55 23 * * * https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js, tag=Sub-Store Sync, img-url=https://raw.githubusercontent.com/58xinian/icon/master/Sub-Store1.png" + ] +} \ No newline at end of file diff --git a/config/QX.snippet b/config/QX.snippet new file mode 100644 index 0000000000..2a1f9a1141 --- /dev/null +++ b/config/QX.snippet @@ -0,0 +1,4 @@ +hostname=sub.store + +^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))) url script-analyze-echo-response https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js +^https?:\/\/sub\.store url script-analyze-echo-response https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js \ No newline at end of file diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000000..6fd46218f8 --- /dev/null +++ b/config/README.md @@ -0,0 +1,62 @@ +# Sub-Store 配置指南 + +## 查看更新说明: + +Sub-Store Releases: [`https://github.com/sub-store-org/Sub-Store/releases`](https://github.com/sub-store-org/Sub-Store/releases) + +Telegram 频道: [`https://t.me/cool_scripts` ](https://t.me/cool_scripts) + +## 服务器/云平台/Docker/Android 版 + +https://xream.notion.site/Sub-Store-abe6a96944724dc6a36833d5c9ab7c87 + +## App 版 + +### 1. Loon +安装使用 插件 [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Loon.plugin`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Loon.plugin) 即可。 + +### 2. Surge + +#### 关于 Surge 的格外说明 + +Surge Mac 版如何支持 SSR, 如何去除 HTTP 传输层以支持 类似 VMess HTTP 节点等 请查看 [链接参数说明](https://github.com/sub-store-org/Sub-Store/wiki/%E9%93%BE%E6%8E%A5%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E) + +定时处理订阅 功能, 避免 App 内拉取超时, 请查看 [定时处理订阅](https://t.me/zhetengsha/1449) + +0. 最新 Surge iOS TestFlight 版本 可使用 Beta 版(支持最新 Surge iOS TestFlight 版本的特性): [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Beta.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Beta.sgmodule) + +1. 官方默认版模块(支持 App 内使用编辑参数): [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge.sgmodule) + +> 最新版 Surge 已删除 `ability: http-client-policy` 参数, 模块暂不做修改, 对测落地功能无影响 + +2. 经典版, 不支持编辑参数, 固定带 ability 参数版本, 使用 jsc 引擎时, 可能会爆内存, 如果需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 请使用此带 ability 参数版本: [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-ability.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-ability.sgmodule) + +3. 经典版, 不支持编辑参数, 固定不带 ability 参数版本: [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule) + + +### 3. QX +订阅 重写 [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/QX.snippet`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/QX.snippet) 即可。 + +定时任务: [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/QX-Task.json`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/QX-Task.json) + +### 4. Stash +安装使用 覆写 [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Stash.stoverride`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Stash.stoverride) 即可。 + +### 5. Shadowrocket +安装使用 模块 [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule) 即可。 + +### 6. Egern +安装使用 模块 [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Egern.yaml`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Egern.yaml) 即可。 + +## 使用 Sub-Store +1. 使用 Safari 打开这个 https://sub.store 如网页正常打开并且未弹出任何错误提示,说明 Sub-Store 已经配置成功。 +2. 可以把 Sub-Store 添加到主屏幕,即可获得类似于 APP 的使用体验。 +3. 更详细的使用指南请参考[文档](https://www.notion.so/Sub-Store-6259586994d34c11a4ced5c406264b46)。 + +## 链接参数说明 + +https://github.com/sub-store-org/Sub-Store/wiki/%E9%93%BE%E6%8E%A5%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E + +## 脚本使用说明 + +https://github.com/sub-store-org/Sub-Store/wiki/%E8%84%9A%E6%9C%AC%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E diff --git a/config/Stash.stoverride b/config/Stash.stoverride new file mode 100644 index 0000000000..91fb19967d --- /dev/null +++ b/config/Stash.stoverride @@ -0,0 +1,37 @@ +name: Sub-Store +desc: 高级订阅管理工具 @Peng-YM. 定时任务默认为每天 23 点 55 分. 定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置' +icon: https://raw.githubusercontent.com/cc63/ICON/main/Sub-Store.png + +http: + mitm: + - sub.store + script: + - match: ^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))) + name: sub-store-1 + type: request + require-body: true + timeout: 120 + - match: ^https?:\/\/sub\.store + name: sub-store-0 + type: request + require-body: true + timeout: 120 + +cron: + script: + - name: cron-sync-artifacts + cron: "55 23 * * *" + timeout: 120 + +script-providers: + sub-store-0: + url: https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js + interval: 86400 + + sub-store-1: + url: https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js + interval: 86400 + + cron-sync-artifacts: + url: https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js + interval: 86400 diff --git a/config/Surge-Beta.sgmodule b/config/Surge-Beta.sgmodule new file mode 100644 index 0000000000..6e18828e22 --- /dev/null +++ b/config/Surge-Beta.sgmodule @@ -0,0 +1,17 @@ +#!name=Sub-Store(β) +#!desc=支持 Surge 正式版的参数设置功能. 测落地功能 ability: http-client-policy, 同步配置的定时 cronexp: 55 23 * * * +#!category=订阅管理 +#!arguments=ability:http-client-policy,cronexp:55 23 * * *,sync:"Sub-Store Sync",timeout:120,engine:auto,produce:"# Sub-Store Produce",produce_cronexp:50 */6 * * *,produce_sub:"sub1,sub2",produce_col:"col1,col2" +#!arguments-desc=\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置'\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅 + +[MITM] +hostname = %APPEND% sub.store + +[Script] +Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js,requires-body=true,timeout={{{timeout}}},ability="{{{ability}}}",engine={{{engine}}} + +Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js,requires-body=true,timeout={{{timeout}}},engine={{{engine}}} + +{{{sync}}}=type=cron,cronexp="{{{cronexp}}}",wake-system=1,timeout={{{timeout}}},script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js,engine={{{engine}}} + +{{{produce}}}=type=cron,cronexp="{{{produce_cronexp}}}",wake-system=1,timeout={{{timeout}}},script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js,engine={{{engine}}},argument="sub={{{produce_sub}}}&col={{{produce_col}}}" \ No newline at end of file diff --git a/config/Surge-Noability.sgmodule b/config/Surge-Noability.sgmodule new file mode 100644 index 0000000000..024263777e --- /dev/null +++ b/config/Surge-Noability.sgmodule @@ -0,0 +1,13 @@ +#!name=Sub-Store +#!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 可以用带 ability 参数. 定时任务默认为每天 23 点 55 分. 定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置' +#!category=订阅管理 + +[MITM] +hostname = %APPEND% sub.store + +[Script] +# 主程序 已经去掉 Sub-Store Core 的参数 [,ability=http-client-policy] 不会爆内存,这个参数在 Surge 非常占用内存; 如果不需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 则可以使用此脚本 +Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js,requires-body=true,timeout=120 +Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js,requires-body=true,timeout=120 + +Sub-Store Sync=type=cron,cronexp=55 23 * * *,wake-system=1,timeout=120,script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js diff --git a/config/Surge-ability.sgmodule b/config/Surge-ability.sgmodule new file mode 100644 index 0000000000..3eb98f172a --- /dev/null +++ b/config/Surge-ability.sgmodule @@ -0,0 +1,12 @@ +#!name=Sub-Store +#!desc=高级订阅管理工具 @Peng-YM 带 ability 参数版本, 使用 jsc 引擎时, 可能会爆内存, 如果不需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 可以用不带 ability 参数版本. 定时任务默认为每天 23 点 55 分. 定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置' +#!category=订阅管理 + +[MITM] +hostname = %APPEND% sub.store + +[Script] +Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js,requires-body=true,timeout=120,ability=http-client-policy +Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js,requires-body=true,timeout=120 + +Sub-Store Sync=type=cron,cronexp=55 23 * * *,wake-system=1,timeout=120,script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js diff --git a/config/Surge.sgmodule b/config/Surge.sgmodule new file mode 100644 index 0000000000..82a17d6766 --- /dev/null +++ b/config/Surge.sgmodule @@ -0,0 +1,17 @@ +#!name=Sub-Store +#!desc=支持 Surge 正式版的参数设置功能. 测落地功能 ability: http-client-policy, 同步配置的定时 cronexp: 55 23 * * * +#!category=订阅管理 +#!arguments=ability:http-client-policy,cronexp:55 23 * * *,sync:"Sub-Store Sync",timeout:120,engine:auto,produce:"# Sub-Store Produce",produce_cronexp:50 */6 * * *,produce_sub:"sub1,sub2",produce_col:"col1,col2" +#!arguments-desc=\n1️⃣ ability\n\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n填写任意其他值关闭\n\n2️⃣ cronexp\n\n同步配置定时任务\n默认为每天 23 点 55 分\n\n定时任务指定时将订阅/文件上传到私有 Gist. 在前端, 叫做 '同步' 或 '同步配置'\n\n3️⃣ sync\n\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务\n\n4️⃣ timeout\n\n脚本超时, 单位为秒\n\n5️⃣ engine\n\n默认为自动使用 webview 引擎, 可设为指定 jsc, 但 jsc 容易爆内存\n\n6️⃣ produce\n\n自定义处理订阅的定时任务名\n一般用于定时处理耗时较长的订阅, 以更新缓存\n这样 Surge 中拉取的时候就能用到缓存, 不至于总是超时\n若设为 # 可取消此定时任务\n默认不开启\n\n7️⃣ produce_cronexp\n\n配置处理订阅的定时任务\n\n默认为每 6 小时\n\n9️⃣ produce_sub\n\n自定义需定时处理的单条订阅名\n多个用 , 连接\n\n🔟 produce_col\n\n自定义需定时处理的组合订阅名\n多个用 , 连接\n\n⚠️ 注意: 是 名称(name) 不是 显示名称(displayName)\n如果名称需要编码, 请编码后再用 , 连接\n顺序: 并发执行单条订阅, 然后并发执行组合订阅 + +[MITM] +hostname = %APPEND% sub.store + +[Script] +Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-1.min.js,requires-body=true,timeout={{{timeout}}},ability="{{{ability}}}",engine={{{engine}}} + +Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/sub-store-0.min.js,requires-body=true,timeout={{{timeout}}},engine={{{engine}}} + +{{{sync}}}=type=cron,cronexp="{{{cronexp}}}",wake-system=1,timeout={{{timeout}}},script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js,engine={{{engine}}} + +{{{produce}}}=type=cron,cronexp="{{{produce_cronexp}}}",wake-system=1,timeout={{{timeout}}},script-path=https://raw.githubusercontent.com/sub-store-org/Sub-Store/release/cron-sync-artifacts.min.js,engine={{{engine}}},argument="sub={{{produce_sub}}}&col={{{produce_col}}}" \ No newline at end of file diff --git a/nginx/front.conf b/nginx/front.conf new file mode 100644 index 0000000000..7f37b53565 --- /dev/null +++ b/nginx/front.conf @@ -0,0 +1,40 @@ +upstream api { + server 0.0.0.0:3000; +} + +server { + listen 6080; +# allow 127.0.0.1; +# allow 0.0.0.0; +# deny all; + + gzip on; + gzip_static on; + gzip_types text/plain application/json application/javascript application/x-javascript text/css application/xml text/javascript; + gzip_proxied any; + gzip_vary on; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.0; + + location / { + root /Sub-Store/web/dist; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://api; + } + + location /download { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://api; + } + +} \ No newline at end of file diff --git a/scripts/demo.js b/scripts/demo.js new file mode 100644 index 0000000000..78bbad07e5 --- /dev/null +++ b/scripts/demo.js @@ -0,0 +1,314 @@ +function operator(proxies = [], targetPlatform, context) { + // 支持快捷操作 不一定要写一个 function + // 可参考 https://t.me/zhetengsha/970 + // https://t.me/zhetengsha/1009 + + // proxies 为传入的内部节点数组 + // 可在预览界面点击节点查看 JSON 结构 或查看 `target=JSON` 的通用订阅 + // 0. 结构大致参考了 Clash.Meta(mihomo), 可参考 mihomo 的文档, 例如 `xudp`, `smux` 都可以自己设置. 但是有私货, 下面是我能想起来的一些私货 + // 1. `_no-resolve` 为不解析域名 + // 2. 域名解析后 会多一个 `_resolved` 字段, 表示是否解析成功 + // 3. 域名解析后会有`_IPv4`, `_IPv6`, `_IP`(若有多个步骤, 只取第一次成功的 v4 或 v6 数据), `_IP4P`(若解析类型为 IPv6 且符合 IP4P 类型, 将自动转换), `_domain` 字段, `_resolved_ips` 为解析出的所有 IP + // 4. 节点字段 `exec` 为 `ssr-local` 路径, 默认 `/usr/local/bin/ssr-local`; 端口从 10000 开始递增(暂不支持配置) + // 5. `_subName` 为单条订阅名, `_subDisplayName` 为单条订阅显示名 + // 6. `_collectionName` 为组合订阅名, `_collectionDisplayName` 为组合订阅显示名 + // 7. `tls-fingerprint` 为 tls 指纹 + // 8. `underlying-proxy` 为前置代理, 不同平台会自动转换 + // 只给 mihomo 输出的话, `dialer-proxy` 也行 + // 只给 sing-box 输出的话, `detour` 也行 + // 只给 egern 输出的话, `prev_hop` 也行 + // 输出到 Clash/Stash/Shadowrocket 时, 会过滤掉配置了前置代理的节点, 并提示使用对应的功能. + // 9. `trojan`, `tuic`, `hysteria`, `hysteria2`, `juicity` 会在解析时设置 `tls`: true (会使用 tls 类协议的通用逻辑), 输出时删除 + // 10. `sni` 在某些协议里会自动与 `servername` 转换 + // 11. 读取节点的 ca-str 和 _ca (后端文件路径) 字段, 自动计算 fingerprint (参考 https://t.me/zhetengsha/1512) + // 12. 以 Surge 为例, 最新的参数一般我都会跟进, 以 Surge 文档为例, 一些常用的: TUIC/Hysteria 2 的 `ecn`, Snell 的 `reuse` 连接复用, QUIC 策略 block-quic`, Hysteria 2 下载带宽 `down` + // 13. `test-url` 为测延迟链接, `test-timeout` 为测延迟超时 + // 14. `ports` 为端口跳跃, `hop-interval` 变换端口号的时间间隔 + // 15. `ip-version` 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer. 会进行内部转换, 若无法匹配则使用原始值 + // 16. `sing-box` 支持使用 `_network` 来设置 `network`, 例如 `tcp`, `udp` + // 17. `block-quic` 支持 `auto`, `on`, `off`. 不同的平台不一定都支持, 会自动转换 + + // require 为 Node.js 的 require, 在 Node.js 运行环境下 可以用来引入模块 + // 例如在 Node.js 环境下, 将文件内容写入 /tmp/1.txt 文件 + // const fs = eval(`require("fs")`) + // // const path = eval(`require("path")`) + // fs.writeFileSync('/tmp/1.txt', $content, "utf8"); + + // $arguments 为传入的脚本参数 + + // $options 为通过链接传入的参数 + // 例如: { arg1: 'a', arg2: 'b' } + // 可这样传: + // 先这样处理 encodeURIComponent(JSON.stringify({ arg1: 'a', arg2: 'b' })) + // /api/file/foo?$options=%7B%22arg1%22%3A%22a%22%2C%22arg2%22%3A%22b%22%7D + // 或这样传: + // 先这样处理 encodeURIComponent('arg1=a&arg2=b') + // /api/file/foo?$options=arg1%3Da%26arg2%3Db + + // 默认会带上 _req 字段, 结构为 + // { + // method, + // url, + // path, + // query, + // params, + // headers, + // body, + // } + // console.log($options) + + // targetPlatform 为输出的目标平台 + + // lodash + + // $substore 为 OpenAPI + // 参考 https://github.com/Peng-YM/QuanX/blob/master/Tools/OpenAPI/README.md + + // scriptResourceCache 缓存 + // 可参考 https://t.me/zhetengsha/1003 + // const cache = scriptResourceCache + // 设置 + // cache.set('a:1', 1) + // cache.set('a:2', 2) + // 获取 + // cache.get('a:1') + // 支持第二个参数: 自定义过期时间 + // 支持第三个参数: 是否删除过期项 + // cache.get('a:2', 1000, true) + + // 清理 + // cache._cleanup() + // 支持第一个参数: 匹配前缀的项也一起删除 + // 支持第二个参数: 自定义过期时间 + // cache._cleanup('a:', 1000) + + // 关于缓存时长 + + // 拉取 Sub-Store 订阅时, 会自动拉取远程订阅 + + // 远程订阅缓存是 1 小时, 缓存的唯一 key 为 url+ user agent. 可通过前端的刷新按钮刷新缓存. 或使用参数 noCache 来禁用缓存. 例: 内部配置订阅链接时使用 http://a.com#noCache, 外部使用 sub-store 链接时使用 https://sub.store/download/1?noCache=true + + // 当使用相关脚本时, 若在对应的脚本中使用参数开启缓存, 可设置持久化缓存 sub-store-csr-expiration-time 的值来自定义默认缓存时长, 默认为 172800000 (48 * 3600 * 1000, 即 48 小时) + + // 🎈Loon 可在插件中设置 + + // 其他平台同理, 持久化缓存数据在 JSON 里 + + // 当配合脚本使用时, 可以在脚本的前面添加一个脚本操作, 实现保留 1 小时的缓存. 这样比较灵活 + + // async function operator() { + // scriptResourceCache._cleanup(undefined, 1 * 3600 * 1000); + // } + + // ProxyUtils 为节点处理工具 + // 可参考 https://t.me/zhetengsha/1066 + // const ProxyUtils = { + // parse, // 订阅解析 + // process, // 节点操作/文件操作 + // produce, // 输出订阅 + // getRandomPort, // 获取随机端口(参考 ports 端口跳跃的格式 443,8443,5000-6000) + // ipAddress, // https://github.com/beaugunderson/ip-address + // isIPv4, + // isIPv6, + // isIP, + // yaml, // yaml 解析和生成 + // getFlag, // 获取 emoji 旗帜 + // removeFlag, // 移除 emoji 旗帜 + // getISO, // 获取 ISO 3166-1 alpha-2 代码 + // Gist, // Gist 类 + // download, // 内部的下载方法, 见 backend/src/utils/download.js + // downloadFile, // 下载二进制文件, 见 backend/src/utils/download.js + // MMDB, // Node.js 环境 可用于模拟 Surge/Loon 的 $utils.ipasn, $utils.ipaso, $utils.geoip. 具体见 https://t.me/zhetengsha/1269 + // isValidUUID, // 辅助判断是否为有效的 UUID + // } + + // 如果只是为了快速修改或者筛选 可以参考 脚本操作支持节点快捷脚本 https://t.me/zhetengsha/970 和 脚本筛选支持节点快捷脚本 https://t.me/zhetengsha/1009 + // ⚠️ 注意: 函数式(即本文件这样的 function operator() {}) 和快捷操作(下面使用 $server) 只能二选一 + // 示例: 给节点名添加前缀 + // $server.name = `[${ProxyUtils.getISO($server.name)}] ${$server.name}` + // 示例: 给节点名添加旗帜 + // $server.name = `[${ProxyUtils.getFlag($server.name).replace(/🇹🇼/g, '🇼🇸')}] ${ProxyUtils.removeFlag($server.name)}` + + // 示例: 从 sni 文件中读取内容并进行节点操作 + // const sni = await produceArtifact({ + // type: 'file', + // name: 'sni' // 文件名 + // }); + // $server.sni = sni + + // 1. Surge 输出 WireGuard 完整配置 + + // let proxies = await produceArtifact({ + // type: 'subscription', + // name: 'sub', + // platform: 'Surge', + // produceOpts: { + // 'include-unsupported-proxy': true, + // } + // }) + // $content = proxies + + // 2. sing-box + + // 但是一般不需要这样用, 可参考 + // 1. https://t.me/zhetengsha/1111 + // 2. https://t.me/zhetengsha/1070 + // 3. https://t.me/zhetengsha/1241 + + // let singboxProxies = await produceArtifact({ + // type: 'subscription', // type: 'subscription' 或 'collection' + // name: 'sub', // subscription name + // platform: 'sing-box', // target platform + // produceType: 'internal' // 'internal' produces an Array, otherwise produces a String( JSON.parse('JSON String') ) + // }) + + // // JSON + // $content = JSON.stringify({}, null, 2) + + // 3. clash.meta + + // 但是一般不需要这样用, 可参考 + // 1. https://t.me/zhetengsha/1111 + // 2. https://t.me/zhetengsha/1070 + // 3. https://t.me/zhetengsha/1234 + + // let clashMetaProxies = await produceArtifact({ + // type: 'subscription', + // name: 'sub', + // platform: 'ClashMeta', + // produceType: 'internal' // 'internal' produces an Array, otherwise produces a String( ProxyUtils.yaml.safeLoad('YAML String').proxies ) + // }) + + // 4. 一个比较折腾的方案: 在脚本操作中, 把内容同步到另一个 gist + // 见 https://t.me/zhetengsha/1428 + // + // const content = ProxyUtils.produce([...proxies], platform) + + // // YAML + // ProxyUtils.yaml.load('YAML String') + // ProxyUtils.yaml.safeLoad('YAML String') + // $content = ProxyUtils.yaml.safeDump({}) + // $content = ProxyUtils.yaml.dump({}) + + // 一个往文件里插入本地节点的例子: + // const yaml = ProxyUtils.yaml.safeLoad($content ?? $files[0]) + // let clashMetaProxies = await produceArtifact({ + // type: 'collection', + // name: '机场', + // platform: 'ClashMeta', + // produceType: 'internal' + // }) + // yaml.proxies.unshift(...clashMetaProxies) + // $content = ProxyUtils.yaml.dump(yaml) + + // { $content, $files, $options } will be passed to the next operator + // $content is the final content of the file + + // flowUtils 为机场订阅流量信息处理工具 + // 可参考: + // 1. https://t.me/zhetengsha/948 + + // context 为传入的上下文 + // 其中 source 为 订阅和组合订阅的数据, 有三种情况, 按需判断 (若只需要取订阅/组合订阅名称 直接用 `_subName` `_subDisplayName` `_collectionName` `_collectionDisplayName` 即可) + + // 若存在 `source._collection` 且 `source._collection.subscriptions` 中的 key 在 `source` 上也存在, 说明输出结果为组合订阅, 但是脚本设置在单条订阅上 + + // 若存在 `source._collection` 但 `source._collection.subscriptions` 中的 key 在 `source` 上不存在, 说明输出结果为组合订阅, 脚本设置在组合订阅上 + + // 若不存在 `source._collection`, 说明输出结果为单条订阅, 脚本设置在此单条订阅上 + + // 这个历史遗留原因, 是有点复杂. 提供一个例子, 用来取当前脚本所在的组合订阅或单条订阅名称 + + // let name = '' + // for (const [key, value] of Object.entries(env.source)) { + // if (!key.startsWith('_')) { + // name = value.displayName || value.name + // break + // } + // } + // if (!name) { + // const collection = env.source._collection + // name = collection.displayName || collection.name + // } + + // 1. 输出单条订阅 sub-1 时, 该单条订阅中的脚本上下文为: + // { + // "source": { + // "sub-1": { + // "name": "sub-1", + // "displayName": "", + // "mergeSources": "", + // "ignoreFailedRemoteSub": true, + // "process": [], + // "icon": "", + // "source": "local", + // "url": "", + // "content": "", + // "ua": "", + // "display-name": "", + // "useCacheForFailedRemoteSub": false + // } + // }, + // "backend": "Node", + // "version": "2.14.198" + // } + // 2. 输出组合订阅 collection-1 时, 该组合订阅中的脚本上下文为: + // { + // "source": { + // "_collection": { + // "name": "collection-1", + // "displayName": "", + // "mergeSources": "", + // "ignoreFailedRemoteSub": false, + // "icon": "", + // "process": [], + // "subscriptions": [ + // "sub-1" + // ], + // "display-name": "" + // } + // }, + // "backend": "Node", + // "version": "2.14.198" + // } + // 3. 输出组合订阅 collection-1 时, 该组合订阅中的单条订阅 sub-1 中的某个脚本上下文为: + // { + // "source": { + // "sub-1": { + // "name": "sub-1", + // "displayName": "", + // "mergeSources": "", + // "ignoreFailedRemoteSub": true, + // "icon": "", + // "process": [], + // "source": "local", + // "url": "", + // "content": "", + // "ua": "", + // "display-name": "", + // "useCacheForFailedRemoteSub": false + // }, + // "_collection": { + // "name": "collection-1", + // "displayName": "", + // "mergeSources": "", + // "ignoreFailedRemoteSub": false, + // "icon": "", + // "process": [], + // "subscriptions": [ + // "sub-1" + // ], + // "display-name": "" + // } + // }, + // "backend": "Node", + // "version": "2.14.198" + // } + + // 参数说明 + // 可参考 https://github.com/sub-store-org/Sub-Store/wiki/%E9%93%BE%E6%8E%A5%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E + + console.log(JSON.stringify(context, null, 2)); + + return proxies; +} diff --git a/scripts/fancy-characters.js b/scripts/fancy-characters.js new file mode 100644 index 0000000000..8181e5bfbb --- /dev/null +++ b/scripts/fancy-characters.js @@ -0,0 +1,57 @@ +/** + * 节点名改为花里胡哨字体,仅支持英文字符和数字 + * + * 【字体】 + * 可参考:https://www.dute.org/weird-fonts + * serif-bold, serif-italic, serif-bold-italic, sans-serif-regular, sans-serif-bold-italic, script-regular, script-bold, fraktur-regular, fraktur-bold, monospace-regular, double-struck-bold, circle-regular, square-regular, modifier-letter(小写没有 q, 用 ᵠ 替代. 大写缺的太多, 用小写替代) + * + * 【示例】 + * 1️⃣ 设置所有格式为 "serif-bold" + * #type=serif-bold + * + * 2️⃣ 设置字母格式为 "serif-bold",数字格式为 "circle-regular" + * #type=serif-bold&num=circle-regular + */ + +function operator(proxies) { + const { type, num } = $arguments; + const TABLE = { + "serif-bold": ["𝟎","𝟏","𝟐","𝟑","𝟒","𝟓","𝟔","𝟕","𝟖","𝟗","𝐚","𝐛","𝐜","𝐝","𝐞","𝐟","𝐠","𝐡","𝐢","𝐣","𝐤","𝐥","𝐦","𝐧","𝐨","𝐩","𝐪","𝐫","𝐬","𝐭","𝐮","𝐯","𝐰","𝐱","𝐲","𝐳","𝐀","𝐁","𝐂","𝐃","𝐄","𝐅","𝐆","𝐇","𝐈","𝐉","𝐊","𝐋","𝐌","𝐍","𝐎","𝐏","𝐐","𝐑","𝐒","𝐓","𝐔","𝐕","𝐖","𝐗","𝐘","𝐙"] , + "serif-italic": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "𝑎", "𝑏", "𝑐", "𝑑", "𝑒", "𝑓", "𝑔", "ℎ", "𝑖", "𝑗", "𝑘", "𝑙", "𝑚", "𝑛", "𝑜", "𝑝", "𝑞", "𝑟", "𝑠", "𝑡", "𝑢", "𝑣", "𝑤", "𝑥", "𝑦", "𝑧", "𝐴", "𝐵", "𝐶", "𝐷", "𝐸", "𝐹", "𝐺", "𝐻", "𝐼", "𝐽", "𝐾", "𝐿", "𝑀", "𝑁", "𝑂", "𝑃", "𝑄", "𝑅", "𝑆", "𝑇", "𝑈", "𝑉", "𝑊", "𝑋", "𝑌", "𝑍"], + "serif-bold-italic": ["0","1","2","3","4","5","6","7","8","9","𝒂","𝒃","𝒄","𝒅","𝒆","𝒇","𝒈","𝒉","𝒊","𝒋","𝒌","𝒍","𝒎","𝒏","𝒐","𝒑","𝒒","𝒓","𝒔","𝒕","𝒖","𝒗","𝒘","𝒙","𝒚","𝒛","𝑨","𝑩","𝑪","𝑫","𝑬","𝑭","𝑮","𝑯","𝑰","𝑱","𝑲","𝑳","𝑴","𝑵","𝑶","𝑷","𝑸","𝑹","𝑺","𝑻","𝑼","𝑽","𝑾","𝑿","𝒀","𝒁"], + "sans-serif-regular": ["𝟢", "𝟣", "𝟤", "𝟥", "𝟦", "𝟧", "𝟨", "𝟩", "𝟪", "𝟫", "𝖺", "𝖻", "𝖼", "𝖽", "𝖾", "𝖿", "𝗀", "𝗁", "𝗂", "𝗃", "𝗄", "𝗅", "𝗆", "𝗇", "𝗈", "𝗉", "𝗊", "𝗋", "𝗌", "𝗍", "𝗎", "𝗏", "𝗐", "𝗑", "𝗒", "𝗓", "𝖠", "𝖡", "𝖢", "𝖣", "𝖤", "𝖥", "𝖦", "𝖧", "𝖨", "𝖩", "𝖪", "𝖫", "𝖬", "𝖭", "𝖮", "𝖯", "𝖰", "𝖱", "𝖲", "𝖳", "𝖴", "𝖵", "𝖶", "𝖷", "𝖸", "𝖹"], + "sans-serif-bold": ["𝟬","𝟭","𝟮","𝟯","𝟰","𝟱","𝟲","𝟳","𝟴","𝟵","𝗮","𝗯","𝗰","𝗱","𝗲","𝗳","𝗴","𝗵","𝗶","𝗷","𝗸","𝗹","𝗺","𝗻","𝗼","𝗽","𝗾","𝗿","𝘀","𝘁","𝘂","𝘃","𝘄","𝘅","𝘆","𝘇","𝗔","𝗕","𝗖","𝗗","𝗘","𝗙","𝗚","𝗛","𝗜","𝗝","𝗞","𝗟","𝗠","𝗡","𝗢","𝗣","𝗤","𝗥","𝗦","𝗧","𝗨","𝗩","𝗪","𝗫","𝗬","𝗭"], + "sans-serif-italic": ["0","1","2","3","4","5","6","7","8","9","𝘢","𝘣","𝘤","𝘥","𝘦","𝘧","𝘨","𝘩","𝘪","𝘫","𝘬","𝘭","𝘮","𝘯","𝘰","𝘱","𝘲","𝘳","𝘴","𝘵","𝘶","𝘷","𝘸","𝘹","𝘺","𝘻","𝘈","𝘉","𝘊","𝘋","𝘌","𝘍","𝘎","𝘏","𝘐","𝘑","𝘒","𝘓","𝘔","𝘕","𝘖","𝘗","𝘘","𝘙","𝘚","𝘛","𝘜","𝘝","𝘞","𝘟","𝘠","𝘡"], + "sans-serif-bold-italic": ["0","1","2","3","4","5","6","7","8","9","𝙖","𝙗","𝙘","𝙙","𝙚","𝙛","𝙜","𝙝","𝙞","𝙟","𝙠","𝙡","𝙢","𝙣","𝙤","𝙥","𝙦","𝙧","𝙨","𝙩","𝙪","𝙫","𝙬","𝙭","𝙮","𝙯","𝘼","𝘽","𝘾","𝘿","𝙀","𝙁","𝙂","𝙃","𝙄","𝙅","𝙆","𝙇","𝙈","𝙉","𝙊","𝙋","𝙌","𝙍","𝙎","𝙏","𝙐","𝙑","𝙒","𝙓","𝙔","𝙕"], + "script-regular": ["0","1","2","3","4","5","6","7","8","9","𝒶","𝒷","𝒸","𝒹","ℯ","𝒻","ℊ","𝒽","𝒾","𝒿","𝓀","𝓁","𝓂","𝓃","ℴ","𝓅","𝓆","𝓇","𝓈","𝓉","𝓊","𝓋","𝓌","𝓍","𝓎","𝓏","𝒜","ℬ","𝒞","𝒟","ℰ","ℱ","𝒢","ℋ","ℐ","𝒥","𝒦","ℒ","ℳ","𝒩","𝒪","𝒫","𝒬","ℛ","𝒮","𝒯","𝒰","𝒱","𝒲","𝒳","𝒴","𝒵"], + "script-bold": ["0","1","2","3","4","5","6","7","8","9","𝓪","𝓫","𝓬","𝓭","𝓮","𝓯","𝓰","𝓱","𝓲","𝓳","𝓴","𝓵","𝓶","𝓷","𝓸","𝓹","𝓺","𝓻","𝓼","𝓽","𝓾","𝓿","𝔀","𝔁","𝔂","𝔃","𝓐","𝓑","𝓒","𝓓","𝓔","𝓕","𝓖","𝓗","𝓘","𝓙","𝓚","𝓛","𝓜","𝓝","𝓞","𝓟","𝓠","𝓡","𝓢","𝓣","𝓤","𝓥","𝓦","𝓧","𝓨","𝓩"], + "fraktur-regular": ["0","1","2","3","4","5","6","7","8","9","𝔞","𝔟","𝔠","𝔡","𝔢","𝔣","𝔤","𝔥","𝔦","𝔧","𝔨","𝔩","𝔪","𝔫","𝔬","𝔭","𝔮","𝔯","𝔰","𝔱","𝔲","𝔳","𝔴","𝔵","𝔶","𝔷","𝔄","𝔅","ℭ","𝔇","𝔈","𝔉","𝔊","ℌ","ℑ","𝔍","𝔎","𝔏","𝔐","𝔑","𝔒","𝔓","𝔔","ℜ","𝔖","𝔗","𝔘","𝔙","𝔚","𝔛","𝔜","ℨ"], + "fraktur-bold": ["0","1","2","3","4","5","6","7","8","9","𝖆","𝖇","𝖈","𝖉","𝖊","𝖋","𝖌","𝖍","𝖎","𝖏","𝖐","𝖑","𝖒","𝖓","𝖔","𝖕","𝖖","𝖗","𝖘","𝖙","𝖚","𝖛","𝖜","𝖝","𝖞","𝖟","𝕬","𝕭","𝕮","𝕯","𝕰","𝕱","𝕲","𝕳","𝕴","𝕵","𝕶","𝕷","𝕸","𝕹","𝕺","𝕻","𝕼","𝕽","𝕾","𝕿","𝖀","𝖁","𝖂","𝖃","𝖄","𝖅"], + "monospace-regular": ["𝟶","𝟷","𝟸","𝟹","𝟺","𝟻","𝟼","𝟽","𝟾","𝟿","𝚊","𝚋","𝚌","𝚍","𝚎","𝚏","𝚐","𝚑","𝚒","𝚓","𝚔","𝚕","𝚖","𝚗","𝚘","𝚙","𝚚","𝚛","𝚜","𝚝","𝚞","𝚟","𝚠","𝚡","𝚢","𝚣","𝙰","𝙱","𝙲","𝙳","𝙴","𝙵","𝙶","𝙷","𝙸","𝙹","𝙺","𝙻","𝙼","𝙽","𝙾","𝙿","𝚀","𝚁","𝚂","𝚃","𝚄","𝚅","𝚆","𝚇","𝚈","𝚉"], + "double-struck-bold": ["𝟘","𝟙","𝟚","𝟛","𝟜","𝟝","𝟞","𝟟","𝟠","𝟡","𝕒","𝕓","𝕔","𝕕","𝕖","𝕗","𝕘","𝕙","𝕚","𝕛","𝕜","𝕝","𝕞","𝕟","𝕠","𝕡","𝕢","𝕣","𝕤","𝕥","𝕦","𝕧","𝕨","𝕩","𝕪","𝕫","𝔸","𝔹","ℂ","𝔻","𝔼","𝔽","𝔾","ℍ","𝕀","𝕁","𝕂","𝕃","𝕄","ℕ","𝕆","ℙ","ℚ","ℝ","𝕊","𝕋","𝕌","𝕍","𝕎","𝕏","𝕐","ℤ"], + "circle-regular": ["⓪","①","②","③","④","⑤","⑥","⑦","⑧","⑨","ⓐ","ⓑ","ⓒ","ⓓ","ⓔ","ⓕ","ⓖ","ⓗ","ⓘ","ⓙ","ⓚ","ⓛ","ⓜ","ⓝ","ⓞ","ⓟ","ⓠ","ⓡ","ⓢ","ⓣ","ⓤ","ⓥ","ⓦ","ⓧ","ⓨ","ⓩ","Ⓐ","Ⓑ","Ⓒ","Ⓓ","Ⓔ","Ⓕ","Ⓖ","Ⓗ","Ⓘ","Ⓙ","Ⓚ","Ⓛ","Ⓜ","Ⓝ","Ⓞ","Ⓟ","Ⓠ","Ⓡ","Ⓢ","Ⓣ","Ⓤ","Ⓥ","Ⓦ","Ⓧ","Ⓨ","Ⓩ"], + "square-regular": ["0","1","2","3","4","5","6","7","8","9","🄰","🄱","🄲","🄳","🄴","🄵","🄶","🄷","🄸","🄹","🄺","🄻","🄼","🄽","🄾","🄿","🅀","🅁","🅂","🅃","🅄","🅅","🅆","🅇","🅈","🅉","🄰","🄱","🄲","🄳","🄴","🄵","🄶","🄷","🄸","🄹","🄺","🄻","🄼","🄽","🄾","🄿","🅀","🅁","🅂","🅃","🅄","🅅","🅆","🅇","🅈","🅉"], + "modifier-letter": ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", "ᵃ", "ᵇ", "ᶜ", "ᵈ", "ᵉ", "ᶠ", "ᵍ", "ʰ", "ⁱ", "ʲ", "ᵏ", "ˡ", "ᵐ", "ⁿ", "ᵒ", "ᵖ", "ᵠ", "ʳ", "ˢ", "ᵗ", "ᵘ", "ᵛ", "ʷ", "ˣ", "ʸ", "ᶻ", "ᴬ", "ᴮ", "ᶜ", "ᴰ", "ᴱ", "ᶠ", "ᴳ", "ʰ", "ᴵ", "ᴶ", "ᴷ", "ᴸ", "ᴹ", "ᴺ", "ᴼ", "ᴾ", "ᵠ", "ᴿ", "ˢ", "ᵀ", "ᵁ", "ᵛ", "ᵂ", "ˣ", "ʸ", "ᶻ"], + }; + + // charCode => index in `TABLE` + const INDEX = { "48": 0, "49": 1, "50": 2, "51": 3, "52": 4, "53": 5, "54": 6, "55": 7, "56": 8, "57": 9, "65": 36, "66": 37, "67": 38, "68": 39, "69": 40, "70": 41, "71": 42, "72": 43, "73": 44, "74": 45, "75": 46, "76": 47, "77": 48, "78": 49, "79": 50, "80": 51, "81": 52, "82": 53, "83": 54, "84": 55, "85": 56, "86": 57, "87": 58, "88": 59, "89": 60, "90": 61, "97": 10, "98": 11, "99": 12, "100": 13, "101": 14, "102": 15, "103": 16, "104": 17, "105": 18, "106": 19, "107": 20, "108": 21, "109": 22, "110": 23, "111": 24, "112": 25, "113": 26, "114": 27, "115": 28, "116": 29, "117": 30, "118": 31, "119": 32, "120": 33, "121": 34, "122": 35 }; + + return proxies.map(p => { + p.name = [...p.name].map(c => { + if (/[a-zA-Z0-9]/.test(c)) { + const code = c.charCodeAt(0); + const index = INDEX[code]; + if (isNumber(code) && num) { + return TABLE[num][index]; + } else { + return TABLE[type][index]; + } + } + return c; + }).join(""); + return p; + }) +} + +function isNumber(code) { return code >= 48 && code <= 57; } \ No newline at end of file diff --git a/scripts/ip-flag-node.js b/scripts/ip-flag-node.js new file mode 100644 index 0000000000..650ded1c0c --- /dev/null +++ b/scripts/ip-flag-node.js @@ -0,0 +1,79 @@ +const $ = $substore; + +const {onlyFlagIP = true} = $arguments + +async function operator(proxies) { + const BATCH_SIZE = 10; + + let i = 0; + while (i < proxies.length) { + const batch = proxies.slice(i, i + BATCH_SIZE); + await Promise.all(batch.map(async proxy => { + if (onlyFlagIP && !ProxyUtils.isIP(proxy.server)) return; + try { + // remove the original flag + let proxyName = removeFlag(proxy.name); + + // query ip-api + const countryCode = await queryIpApi(proxy); + + proxyName = getFlagEmoji(countryCode) + ' ' + proxyName; + proxy.name = proxyName; + } catch (err) { + // TODO: + } + })); + + await sleep(1000); + i += BATCH_SIZE; + } + return proxies; +} + + +async function queryIpApi(proxy) { + const ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:78.0) Gecko/20100101 Firefox/78.0"; + const headers = { + "User-Agent": ua + }; + const result = new Promise((resolve, reject) => { + const url = + `http://ip-api.com/json/${encodeURIComponent(proxy.server)}?lang=zh-CN`; + $.http.get({ + url, + headers, + }).then(resp => { + const data = JSON.parse(resp.body); + if (data.status === "success") { + resolve(data.countryCode); + } else { + reject(new Error(data.message)); + } + }).catch(err => { + console.log(err); + reject(err); + }); + }); + return result; +} + +function getFlagEmoji(countryCode) { + const codePoints = countryCode + .toUpperCase() + .split('') + .map(char => 127397 + char.charCodeAt()); + return String + .fromCodePoint(...codePoints) + .replace(/🇹🇼/g, '🇨🇳'); +} + +function removeFlag(str) { + return str + .replace(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/g, '') + .trim(); +} + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + diff --git a/scripts/ip-flag.js b/scripts/ip-flag.js new file mode 100644 index 0000000000..bda8c792f6 --- /dev/null +++ b/scripts/ip-flag.js @@ -0,0 +1,175 @@ +const RESOURCE_CACHE_KEY = '#sub-store-cached-resource'; +const CACHE_EXPIRATION_TIME_MS = 10 * 60 * 1000; +const $ = $substore; + +class ResourceCache { + constructor(expires) { + this.expires = expires; + if (!$.read(RESOURCE_CACHE_KEY)) { + $.write('{}', RESOURCE_CACHE_KEY); + } + this.resourceCache = JSON.parse($.read(RESOURCE_CACHE_KEY)); + this._cleanup(); + } + + _cleanup() { + // clear obsolete cached resource + let clear = false; + Object.entries(this.resourceCache).forEach((entry) => { + const [id, updated] = entry; + if (!updated.time) { + // clear old version cache + delete this.resourceCache[id]; + $.delete(`#${id}`); + clear = true; + } + if (new Date().getTime() - updated.time > this.expires) { + delete this.resourceCache[id]; + clear = true; + } + }); + if (clear) this._persist(); + } + + revokeAll() { + this.resourceCache = {}; + this._persist(); + } + + _persist() { + $.write(JSON.stringify(this.resourceCache), RESOURCE_CACHE_KEY); + } + + get(id) { + const updated = this.resourceCache[id] && this.resourceCache[id].time; + if (updated && new Date().getTime() - updated <= this.expires) { + return this.resourceCache[id].data; + } + return null; + } + + set(id, value) { + this.resourceCache[id] = { time: new Date().getTime(), data: value } + this._persist(); + } +} + +const resourceCache = new ResourceCache(CACHE_EXPIRATION_TIME_MS); + +async function operator(proxies) { + const { isLoon, isSurge } = $substore.env; + let support = false; + if (isLoon) { + support = true; + } else if (isSurge) { + const build = $environment['surge-build']; + if (build && parseInt(build) >= 2407) { + support = true; + } + } + + if (support) { + const batches = []; + const BATCH_SIZE = 10; + + let i = 0; + while (i < proxies.length) { + const batch = proxies.slice(i, i + BATCH_SIZE); + await Promise.all(batch.map(async proxy => { + try { + // remove the original flag + let proxyName = removeFlag(proxy.name); + + // query ip-api + const countryCode = await queryIpApi(proxy); + + proxyName = getFlagEmoji(countryCode) + ' ' + proxyName; + proxy.name = proxyName; + } catch (err) { + // TODO: + } + })); + + await sleep(1000); + i += BATCH_SIZE; + } + } else { + $.error(`IP Flag only supports Loon and Surge!`); + } + return proxies; +} + +const tasks = new Map(); +async function queryIpApi(proxy) { + const id = getId(proxy); + if (tasks.has(id)) { + return tasks.get(id); + } + + const ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:78.0) Gecko/20100101 Firefox/78.0"; + const headers = { + "User-Agent": ua + }; + const { isLoon } = $substore.env; + const target = isLoon ? "Loon" : "Surge"; + const result = new Promise((resolve, reject) => { + const cached = resourceCache.get(id); + if (cached) { + resolve(cached); + } + const url = `http://ip-api.com/json`; + let node = ProxyUtils.produce([proxy], target); + + // Loon 需要去掉节点名字 + if (isLoon) { + const s = node.indexOf("="); + node = node.substring(s + 1); + } + + $.http.get({ + url, + headers, + node + }).then(resp => { + const body = resp.body; + const data = JSON.parse(body); + if (data.status === "success") { + resourceCache.set(id, data.countryCode); + resolve(data.countryCode); + } else { + reject(new Error(data.message)); + } + }).catch(err => { + console.log(err); + reject(err); + }); + }); + tasks.set(id, result); + return result; +} + +function getId(proxy) { + return MD5(`IP-FLAG-${proxy.server}-${proxy.port}`); +} + +function getFlagEmoji(countryCode) { + const codePoints = countryCode + .toUpperCase() + .split('') + .map(char => 127397 + char.charCodeAt()); + return String + .fromCodePoint(...codePoints) + .replace(/🇹🇼/g, '🇨🇳'); +} + +function removeFlag(str) { + return str + .replace(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/g, '') + .trim(); +} + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +var MD5 = function (d) { var r = M(V(Y(X(d), 8 * d.length))); return r.toLowerCase() }; function M(d) { for (var _, m = "0123456789ABCDEF", f = "", r = 0; r < d.length; r++)_ = d.charCodeAt(r), f += m.charAt(_ >>> 4 & 15) + m.charAt(15 & _); return f } function X(d) { for (var _ = Array(d.length >> 2), m = 0; m < _.length; m++)_[m] = 0; for (m = 0; m < 8 * d.length; m += 8)_[m >> 5] |= (255 & d.charCodeAt(m / 8)) << m % 32; return _ } function V(d) { for (var _ = "", m = 0; m < 32 * d.length; m += 8)_ += String.fromCharCode(d[m >> 5] >>> m % 32 & 255); return _ } function Y(d, _) { d[_ >> 5] |= 128 << _ % 32, d[14 + (_ + 64 >>> 9 << 4)] = _; for (var m = 1732584193, f = -271733879, r = -1732584194, i = 271733878, n = 0; n < d.length; n += 16) { var h = m, t = f, g = r, e = i; f = md5_ii(f = md5_ii(f = md5_ii(f = md5_ii(f = md5_hh(f = md5_hh(f = md5_hh(f = md5_hh(f = md5_gg(f = md5_gg(f = md5_gg(f = md5_gg(f = md5_ff(f = md5_ff(f = md5_ff(f = md5_ff(f, r = md5_ff(r, i = md5_ff(i, m = md5_ff(m, f, r, i, d[n + 0], 7, -680876936), f, r, d[n + 1], 12, -389564586), m, f, d[n + 2], 17, 606105819), i, m, d[n + 3], 22, -1044525330), r = md5_ff(r, i = md5_ff(i, m = md5_ff(m, f, r, i, d[n + 4], 7, -176418897), f, r, d[n + 5], 12, 1200080426), m, f, d[n + 6], 17, -1473231341), i, m, d[n + 7], 22, -45705983), r = md5_ff(r, i = md5_ff(i, m = md5_ff(m, f, r, i, d[n + 8], 7, 1770035416), f, r, d[n + 9], 12, -1958414417), m, f, d[n + 10], 17, -42063), i, m, d[n + 11], 22, -1990404162), r = md5_ff(r, i = md5_ff(i, m = md5_ff(m, f, r, i, d[n + 12], 7, 1804603682), f, r, d[n + 13], 12, -40341101), m, f, d[n + 14], 17, -1502002290), i, m, d[n + 15], 22, 1236535329), r = md5_gg(r, i = md5_gg(i, m = md5_gg(m, f, r, i, d[n + 1], 5, -165796510), f, r, d[n + 6], 9, -1069501632), m, f, d[n + 11], 14, 643717713), i, m, d[n + 0], 20, -373897302), r = md5_gg(r, i = md5_gg(i, m = md5_gg(m, f, r, i, d[n + 5], 5, -701558691), f, r, d[n + 10], 9, 38016083), m, f, d[n + 15], 14, -660478335), i, m, d[n + 4], 20, -405537848), r = md5_gg(r, i = md5_gg(i, m = md5_gg(m, f, r, i, d[n + 9], 5, 568446438), f, r, d[n + 14], 9, -1019803690), m, f, d[n + 3], 14, -187363961), i, m, d[n + 8], 20, 1163531501), r = md5_gg(r, i = md5_gg(i, m = md5_gg(m, f, r, i, d[n + 13], 5, -1444681467), f, r, d[n + 2], 9, -51403784), m, f, d[n + 7], 14, 1735328473), i, m, d[n + 12], 20, -1926607734), r = md5_hh(r, i = md5_hh(i, m = md5_hh(m, f, r, i, d[n + 5], 4, -378558), f, r, d[n + 8], 11, -2022574463), m, f, d[n + 11], 16, 1839030562), i, m, d[n + 14], 23, -35309556), r = md5_hh(r, i = md5_hh(i, m = md5_hh(m, f, r, i, d[n + 1], 4, -1530992060), f, r, d[n + 4], 11, 1272893353), m, f, d[n + 7], 16, -155497632), i, m, d[n + 10], 23, -1094730640), r = md5_hh(r, i = md5_hh(i, m = md5_hh(m, f, r, i, d[n + 13], 4, 681279174), f, r, d[n + 0], 11, -358537222), m, f, d[n + 3], 16, -722521979), i, m, d[n + 6], 23, 76029189), r = md5_hh(r, i = md5_hh(i, m = md5_hh(m, f, r, i, d[n + 9], 4, -640364487), f, r, d[n + 12], 11, -421815835), m, f, d[n + 15], 16, 530742520), i, m, d[n + 2], 23, -995338651), r = md5_ii(r, i = md5_ii(i, m = md5_ii(m, f, r, i, d[n + 0], 6, -198630844), f, r, d[n + 7], 10, 1126891415), m, f, d[n + 14], 15, -1416354905), i, m, d[n + 5], 21, -57434055), r = md5_ii(r, i = md5_ii(i, m = md5_ii(m, f, r, i, d[n + 12], 6, 1700485571), f, r, d[n + 3], 10, -1894986606), m, f, d[n + 10], 15, -1051523), i, m, d[n + 1], 21, -2054922799), r = md5_ii(r, i = md5_ii(i, m = md5_ii(m, f, r, i, d[n + 8], 6, 1873313359), f, r, d[n + 15], 10, -30611744), m, f, d[n + 6], 15, -1560198380), i, m, d[n + 13], 21, 1309151649), r = md5_ii(r, i = md5_ii(i, m = md5_ii(m, f, r, i, d[n + 4], 6, -145523070), f, r, d[n + 11], 10, -1120210379), m, f, d[n + 2], 15, 718787259), i, m, d[n + 9], 21, -343485551), m = safe_add(m, h), f = safe_add(f, t), r = safe_add(r, g), i = safe_add(i, e) } return Array(m, f, r, i) } function md5_cmn(d, _, m, f, r, i) { return safe_add(bit_rol(safe_add(safe_add(_, d), safe_add(f, i)), r), m) } function md5_ff(d, _, m, f, r, i, n) { return md5_cmn(_ & m | ~_ & f, d, _, r, i, n) } function md5_gg(d, _, m, f, r, i, n) { return md5_cmn(_ & f | m & ~f, d, _, r, i, n) } function md5_hh(d, _, m, f, r, i, n) { return md5_cmn(_ ^ m ^ f, d, _, r, i, n) } function md5_ii(d, _, m, f, r, i, n) { return md5_cmn(m ^ (_ | ~f), d, _, r, i, n) } function safe_add(d, _) { var m = (65535 & d) + (65535 & _); return (d >> 16) + (_ >> 16) + (m >> 16) << 16 | 65535 & m } function bit_rol(d, _) { return d << _ | d >>> 32 - _ } \ No newline at end of file diff --git a/scripts/media-filter.js b/scripts/media-filter.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/revert.js b/scripts/revert.js new file mode 100644 index 0000000000..c64cc1b712 --- /dev/null +++ b/scripts/revert.js @@ -0,0 +1,5 @@ +const $ = API() +$.write("{}", "#sub-store") +$.done() + +function ENV(){const e="function"==typeof require&&"undefined"!=typeof $jsbox;return{isQX:"undefined"!=typeof $task,isLoon:"undefined"!=typeof $loon,isSurge:"undefined"!=typeof $httpClient&&"undefined"!=typeof $utils,isBrowser:"undefined"!=typeof document,isNode:"function"==typeof require&&!e,isJSBox:e,isRequest:"undefined"!=typeof $request,isScriptable:"undefined"!=typeof importModule}}function HTTP(e={baseURL:""}){const{isQX:t,isLoon:s,isSurge:o,isScriptable:n,isNode:i,isBrowser:r}=ENV(),u=/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;const a={};return["GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"].forEach(h=>a[h.toLowerCase()]=(a=>(function(a,h){h="string"==typeof h?{url:h}:h;const d=e.baseURL;d&&!u.test(h.url||"")&&(h.url=d?d+h.url:h.url),h.body&&h.headers&&!h.headers["Content-Type"]&&(h.headers["Content-Type"]="application/x-www-form-urlencoded");const l=(h={...e,...h}).timeout,c={onRequest:()=>{},onResponse:e=>e,onTimeout:()=>{},...h.events};let f,p;if(c.onRequest(a,h),t)f=$task.fetch({method:a,...h});else if(s||o||i)f=new Promise((e,t)=>{(i?require("request"):$httpClient)[a.toLowerCase()](h,(s,o,n)=>{s?t(s):e({statusCode:o.status||o.statusCode,headers:o.headers,body:n})})});else if(n){const e=new Request(h.url);e.method=a,e.headers=h.headers,e.body=h.body,f=new Promise((t,s)=>{e.loadString().then(s=>{t({statusCode:e.response.statusCode,headers:e.response.headers,body:s})}).catch(e=>s(e))})}else r&&(f=new Promise((e,t)=>{fetch(h.url,{method:a,headers:h.headers,body:h.body}).then(e=>e.json()).then(t=>e({statusCode:t.status,headers:t.headers,body:t.data})).catch(t)}));const y=l?new Promise((e,t)=>{p=setTimeout(()=>(c.onTimeout(),t(`${a} URL: ${h.url} exceeds the timeout ${l} ms`)),l)}):null;return(y?Promise.race([y,f]).then(e=>(clearTimeout(p),e)):f).then(e=>c.onResponse(e))})(h,a))),a}function API(e="untitled",t=!1){const{isQX:s,isLoon:o,isSurge:n,isNode:i,isJSBox:r,isScriptable:u}=ENV();return new class{constructor(e,t){this.name=e,this.debug=t,this.http=HTTP(),this.env=ENV(),this.node=(()=>{if(i){return{fs:require("fs")}}return null})(),this.initCache();Promise.prototype.delay=function(e){return this.then(function(t){return((e,t)=>new Promise(function(s){setTimeout(s.bind(null,t),e)}))(e,t)})}}initCache(){if(s&&(this.cache=JSON.parse($prefs.valueForKey(this.name)||"{}")),(o||n)&&(this.cache=JSON.parse($persistentStore.read(this.name)||"{}")),i){let e="root.json";this.node.fs.existsSync(e)||this.node.fs.writeFileSync(e,JSON.stringify({}),{flag:"wx"},e=>console.log(e)),this.root={},e=`${this.name}.json`,this.node.fs.existsSync(e)?this.cache=JSON.parse(this.node.fs.readFileSync(`${this.name}.json`)):(this.node.fs.writeFileSync(e,JSON.stringify({}),{flag:"wx"},e=>console.log(e)),this.cache={})}}persistCache(){const e=JSON.stringify(this.cache,null,2);s&&$prefs.setValueForKey(e,this.name),(o||n)&&$persistentStore.write(e,this.name),i&&(this.node.fs.writeFileSync(`${this.name}.json`,e,{flag:"w"},e=>console.log(e)),this.node.fs.writeFileSync("root.json",JSON.stringify(this.root,null,2),{flag:"w"},e=>console.log(e)))}write(e,t){if(this.log(`SET ${t}`),-1!==t.indexOf("#")){if(t=t.substr(1),n||o)return $persistentStore.write(e,t);if(s)return $prefs.setValueForKey(e,t);i&&(this.root[t]=e)}else this.cache[t]=e;this.persistCache()}read(e){return this.log(`READ ${e}`),-1===e.indexOf("#")?this.cache[e]:(e=e.substr(1),n||o?$persistentStore.read(e):s?$prefs.valueForKey(e):i?this.root[e]:void 0)}delete(e){if(this.log(`DELETE ${e}`),-1!==e.indexOf("#")){if(e=e.substr(1),n||o)return $persistentStore.write(null,e);if(s)return $prefs.removeValueForKey(e);i&&delete this.root[e]}else delete this.cache[e];this.persistCache()}notify(e,t="",a="",h={}){const d=h["open-url"],l=h["media-url"];if(s&&$notify(e,t,a,h),n&&$notification.post(e,t,a+`${l?"\n多媒体:"+l:""}`,{url:d}),o){let s={};d&&(s.openUrl=d),l&&(s.mediaUrl=l),"{}"===JSON.stringify(s)?$notification.post(e,t,a):$notification.post(e,t,a,s)}if(i||u){const s=a+(d?`\n点击跳转: ${d}`:"")+(l?`\n多媒体: ${l}`:"");if(r){require("push").schedule({title:e,body:(t?t+"\n":"")+s})}else console.log(`${e}\n${t}\n${s}\n\n`)}}log(e){this.debug&&console.log(`[${this.name}] LOG: ${this.stringify(e)}`)}info(e){console.log(`[${this.name}] INFO: ${this.stringify(e)}`)}error(e){console.log(`[${this.name}] ERROR: ${this.stringify(e)}`)}wait(e){return new Promise(t=>setTimeout(t,e))}done(e={}){s||o||n?$done(e):i&&!r&&"undefined"!=typeof $context&&($context.headers=e.headers,$context.statusCode=e.statusCode,$context.body=e.body)}stringify(e){if("string"==typeof e||e instanceof String)return e;try{return JSON.stringify(e,null,2)}catch(e){return"[object Object]"}}}(e,t)} diff --git a/scripts/tls-fingerprint.js b/scripts/tls-fingerprint.js new file mode 100644 index 0000000000..20838a9bcf --- /dev/null +++ b/scripts/tls-fingerprint.js @@ -0,0 +1,12 @@ +/** + * 为节点添加 tls 证书指纹 + * 示例 + * #fingerprint=... + */ +function operator(proxies) { + const { fingerprint } = $arguments; + proxies.forEach(proxy => { + proxy['tls-fingerprint'] = fingerprint; + }); + return proxies; +} \ No newline at end of file diff --git a/scripts/udp-filter.js b/scripts/udp-filter.js new file mode 100644 index 0000000000..7bd76af07a --- /dev/null +++ b/scripts/udp-filter.js @@ -0,0 +1,6 @@ +/** + * 过滤 UDP 节点 + */ +function filter(proxies) { + return proxies.map(p => p.udp); +} diff --git a/scripts/vmess-ws-obfs-host.js b/scripts/vmess-ws-obfs-host.js new file mode 100644 index 0000000000..58c45c5596 --- /dev/null +++ b/scripts/vmess-ws-obfs-host.js @@ -0,0 +1,16 @@ +/** + * 为 VMess WebSocket 节点修改混淆 host + * 示例 + * #host=google.com + */ +function operator(proxies) { + const { host } = $arguments; + proxies.forEach(p => { + if (p.type === 'vmess' && p.network === 'ws') { + p["ws-opts"] = p["ws-opts"] || {}; + p["ws-opts"]["headers"] = p["ws-opts"]["headers"] || {}; + p["ws-opts"]["headers"]["Host"] = host; + } + }); + return proxies; +} \ No newline at end of file diff --git a/sub-store-web/.gitignore b/sub-store-web/.gitignore deleted file mode 100644 index 403adbc1e5..0000000000 --- a/sub-store-web/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -.DS_Store -node_modules -/dist - - -# local env files -.env.local -.env.*.local - -# Log files -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* - -# Editor directories and files -.idea -.vscode -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/sub-store-web/README.md b/sub-store-web/README.md deleted file mode 100644 index 4f753635d5..0000000000 --- a/sub-store-web/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# sub-store-web - -## Project setup -``` -npm install -``` - -### Compiles and hot-reloads for development -``` -npm run serve -``` - -### Compiles and minifies for production -``` -npm run build -``` - -### Lints and fixes files -``` -npm run lint -``` - -### Customize configuration -See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/sub-store-web/babel.config.js b/sub-store-web/babel.config.js deleted file mode 100644 index e9558405fd..0000000000 --- a/sub-store-web/babel.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - presets: [ - '@vue/cli-plugin-babel/preset' - ] -} diff --git a/sub-store-web/package-lock.json b/sub-store-web/package-lock.json deleted file mode 100644 index 67a0bd8a5c..0000000000 --- a/sub-store-web/package-lock.json +++ /dev/null @@ -1,12117 +0,0 @@ -{ - "name": "sub-store-web", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@ant-design-vue/babel-helper-vue-transform-on": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/@ant-design-vue/babel-helper-vue-transform-on/download/@ant-design-vue/babel-helper-vue-transform-on-1.0.1.tgz", - "integrity": "sha1-0hnZL04fxeet0hHDR8f6AAUYtiM=", - "dev": true - }, - "@ant-design-vue/babel-plugin-jsx": { - "version": "1.0.0-rc.1", - "resolved": "https://registry.npm.taobao.org/@ant-design-vue/babel-plugin-jsx/download/@ant-design-vue/babel-plugin-jsx-1.0.0-rc.1.tgz", - "integrity": "sha1-rlbOy9qfCGkbz5Lf6Y4kFud9dYs=", - "dev": true, - "requires": { - "@ant-design-vue/babel-helper-vue-transform-on": "^1.0.0", - "@babel/helper-module-imports": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "camelcase": "^6.0.0", - "html-tags": "^3.1.0", - "svg-tags": "^1.0.0" - } - }, - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522948158&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/compat-data": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/compat-data/download/@babel/compat-data-7.11.0.tgz", - "integrity": "sha1-6fc+/gmvE1W3I6fzmxG61jfXyZw=", - "dev": true, - "requires": { - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "semver": "^5.5.0" - } - }, - "@babel/core": { - "version": "7.11.1", - "resolved": "https://registry.npm.taobao.org/@babel/core/download/@babel/core-7.11.1.tgz?cache=0&sync_timestamp=1596578849394&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcore%2Fdownload%2F%40babel%2Fcore-7.11.1.tgz", - "integrity": "sha1-LFW2BOc6QNwhsOUmULEcZc8nZkM=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", - "@babel/helper-module-transforms": "^7.11.0", - "@babel/helpers": "^7.10.4", - "@babel/parser": "^7.11.1", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.11.0", - "@babel/types": "^7.11.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/generator": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.11.0.tgz?cache=0&sync_timestamp=1596144430330&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.11.0.tgz", - "integrity": "sha1-S5DHjYwSglAkVoy+g+5smvGTWFw=", - "dev": true, - "requires": { - "@babel/types": "^7.11.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-annotate-as-pure/download/@babel/helper-annotate-as-pure-7.10.4.tgz?cache=0&sync_timestamp=1593521294951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-annotate-as-pure%2Fdownload%2F%40babel%2Fhelper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha1-W/DUlaP3V6w72ki1vzs7ownHK6M=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-builder-binary-assignment-operator-visitor/download/@babel/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz?cache=0&sync_timestamp=1593522960718&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-builder-binary-assignment-operator-visitor%2Fdownload%2F%40babel%2Fhelper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha1-uwt18xv5jL+f8UPBrleLhydK4aM=", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-compilation-targets/download/@babel/helper-compilation-targets-7.10.4.tgz?cache=0&sync_timestamp=1593522816195&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-compilation-targets%2Fdownload%2F%40babel%2Fhelper-compilation-targets-7.10.4.tgz", - "integrity": "sha1-gEro4/BDdmB8x5G51H1UAnYzK9I=", - "dev": true, - "requires": { - "@babel/compat-data": "^7.10.4", - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "levenary": "^1.1.1", - "semver": "^5.5.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-create-class-features-plugin/download/@babel/helper-create-class-features-plugin-7.10.5.tgz", - "integrity": "sha1-n2FEa6gOgkCwpchcb9rIRZ1vJZ0=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.10.5", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-create-regexp-features-plugin/download/@babel/helper-create-regexp-features-plugin-7.10.4.tgz?cache=0&sync_timestamp=1593522973297&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-create-regexp-features-plugin%2Fdownload%2F%40babel%2Fhelper-create-regexp-features-plugin-7.10.4.tgz", - "integrity": "sha1-/dYNiFJGWaC2lZwFeZJeQlcU87g=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-regex": "^7.10.4", - "regexpu-core": "^4.7.0" - } - }, - "@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-define-map/download/@babel/helper-define-map-7.10.5.tgz", - "integrity": "sha1-tTwQ23imQIABUmkrEzkxR6y5uzA=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-explode-assignable-expression/download/@babel/helper-explode-assignable-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522981063&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-explode-assignable-expression%2Fdownload%2F%40babel%2Fhelper-explode-assignable-expression-7.10.4.tgz", - "integrity": "sha1-QKHNkXv/Eoj2malKdbN6Gi29jHw=", - "dev": true, - "requires": { - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593522977138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593521294451&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.10.4.tgz?cache=0&sync_timestamp=1593521294715&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-hoist-variables%2Fdownload%2F%40babel%2Fhelper-hoist-variables-7.10.4.tgz", - "integrity": "sha1-1JsAHR1aaMpeZgTdoBpil/fJOB4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.11.0.tgz?cache=0&sync_timestamp=1596144430473&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-member-expression-to-functions%2Fdownload%2F%40babel%2Fhelper-member-expression-to-functions-7.11.0.tgz", - "integrity": "sha1-rmnIPYTugvS0L5bioJQQk1qPJt8=", - "dev": true, - "requires": { - "@babel/types": "^7.11.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522965782&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.11.0.tgz", - "integrity": "sha1-sW8lAinkchGr3YSzS2RzfCqy01k=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/template": "^7.10.4", - "@babel/types": "^7.11.0", - "lodash": "^4.17.19" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593521296446&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521082372&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-regex": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-regex/download/@babel/helper-regex-7.10.5.tgz?cache=0&sync_timestamp=1594750677873&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-regex%2Fdownload%2F%40babel%2Fhelper-regex-7.10.5.tgz", - "integrity": "sha1-Mt+7eYmQc8QVVXBToZvQVarlCuA=", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-remap-async-to-generator/download/@babel/helper-remap-async-to-generator-7.10.4.tgz?cache=0&sync_timestamp=1593522966172&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-remap-async-to-generator%2Fdownload%2F%40babel%2Fhelper-remap-async-to-generator-7.10.4.tgz", - "integrity": "sha1-/Oi+pOlpC76SMFbe0h5UtOi2jtU=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz?cache=0&sync_timestamp=1593522959591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-replace-supers%2Fdownload%2F%40babel%2Fhelper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.10.4.tgz?cache=0&sync_timestamp=1593522975802&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.10.4.tgz", - "integrity": "sha1-D1zNopRSd6KnotOoIeFTle3PNGE=", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/helper-skip-transparent-expression-wrappers/download/@babel/helper-skip-transparent-expression-wrappers-7.11.0.tgz", - "integrity": "sha1-7sFi8RLC9Y068K8SXju1dmUUZyk=", - "dev": true, - "requires": { - "@babel/types": "^7.11.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha1-+KSRJErPamdhWKxCBykRuoOtCZ8=", - "dev": true, - "requires": { - "@babel/types": "^7.11.0" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.10.4.tgz?cache=0&sync_timestamp=1593521083613&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.10.4.tgz", - "integrity": "sha1-p4x6clHgH2FlEtMbEK3PUq2l4NI=" - }, - "@babel/helper-wrap-function": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-wrap-function/download/@babel/helper-wrap-function-7.10.4.tgz?cache=0&sync_timestamp=1593522965325&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-wrap-function%2Fdownload%2F%40babel%2Fhelper-wrap-function-7.10.4.tgz", - "integrity": "sha1-im9wHqsP8592W1oc/vQJmQ5iS4c=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helpers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helpers/download/@babel/helpers-7.10.4.tgz?cache=0&sync_timestamp=1593522959913&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelpers%2Fdownload%2F%40babel%2Fhelpers-7.10.4.tgz", - "integrity": "sha1-Kr6w1yGv98Cpc3a54fb2XXpHUEQ=", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.10.4.tgz?cache=0&sync_timestamp=1593521095576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhighlight%2Fdownload%2F%40babel%2Fhighlight-7.10.4.tgz", - "integrity": "sha1-fRvf1ldTU4+r5sOFls23bZrGAUM=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.11.3", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.11.3.tgz?cache=0&sync_timestamp=1596915985899&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.11.3.tgz", - "integrity": "sha1-nh6uRnOLzQjiPoZ7q0PnuVKZqPk=" - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-async-generator-functions/download/@babel/plugin-proposal-async-generator-functions-7.10.5.tgz?cache=0&sync_timestamp=1594750682516&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-async-generator-functions%2Fdownload%2F%40babel%2Fplugin-proposal-async-generator-functions-7.10.5.tgz", - "integrity": "sha1-NJHKvy98F5q4IGBs7Cf+0V4OhVg=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-class-properties/download/@babel/plugin-proposal-class-properties-7.10.4.tgz?cache=0&sync_timestamp=1593522963242&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-class-properties%2Fdownload%2F%40babel%2Fplugin-proposal-class-properties-7.10.4.tgz", - "integrity": "sha1-ozv2Mto5ClnHqMVwBF0RFc13iAc=", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-proposal-decorators": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-decorators/download/@babel/plugin-proposal-decorators-7.10.5.tgz?cache=0&sync_timestamp=1594750722573&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-decorators%2Fdownload%2F%40babel%2Fplugin-proposal-decorators-7.10.5.tgz", - "integrity": "sha1-QomLukeLxLGuJCpwOpU6etNQ/7Q=", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-decorators": "^7.10.4" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-dynamic-import/download/@babel/plugin-proposal-dynamic-import-7.10.4.tgz?cache=0&sync_timestamp=1593521093903&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-dynamic-import%2Fdownload%2F%40babel%2Fplugin-proposal-dynamic-import-7.10.4.tgz", - "integrity": "sha1-uleibLmLN3QenVvKG4sN34KR8X4=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-export-namespace-from/download/@babel/plugin-proposal-export-namespace-from-7.10.4.tgz", - "integrity": "sha1-Vw2IO5EDFjez4pWO6jxDjmLAX1Q=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-json-strings/download/@babel/plugin-proposal-json-strings-7.10.4.tgz?cache=0&sync_timestamp=1593521092651&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-json-strings%2Fdownload%2F%40babel%2Fplugin-proposal-json-strings-7.10.4.tgz", - "integrity": "sha1-WT5ZxjUoFgIzvTIbGuvgggwjQds=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-logical-assignment-operators/download/@babel/plugin-proposal-logical-assignment-operators-7.11.0.tgz", - "integrity": "sha1-n4DkgsAwg8hxJd7hACa1hSfqIMg=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-nullish-coalescing-operator/download/@babel/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz?cache=0&sync_timestamp=1593521087263&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-nullish-coalescing-operator%2Fdownload%2F%40babel%2Fplugin-proposal-nullish-coalescing-operator-7.10.4.tgz", - "integrity": "sha1-AqfpYfwy5tWy2wZJ4Bv4Dd7n4Eo=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-numeric-separator/download/@babel/plugin-proposal-numeric-separator-7.10.4.tgz?cache=0&sync_timestamp=1593522970329&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-numeric-separator%2Fdownload%2F%40babel%2Fplugin-proposal-numeric-separator-7.10.4.tgz", - "integrity": "sha1-zhWQ/wplrRKXCmCdeIVemkwa7wY=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-object-rest-spread/download/@babel/plugin-proposal-object-rest-spread-7.11.0.tgz", - "integrity": "sha1-vYH5Wh90Z2DqQ7bC09YrEXkK0K8=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.10.4" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-optional-catch-binding/download/@babel/plugin-proposal-optional-catch-binding-7.10.4.tgz?cache=0&sync_timestamp=1593521089386&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-optional-catch-binding%2Fdownload%2F%40babel%2Fplugin-proposal-optional-catch-binding-7.10.4.tgz", - "integrity": "sha1-Mck4MJ0kp4pJ1o/av/qoY3WFVN0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-optional-chaining/download/@babel/plugin-proposal-optional-chaining-7.11.0.tgz", - "integrity": "sha1-3lhm0GRvav2quKVmOC/joiF1UHY=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-private-methods/download/@babel/plugin-proposal-private-methods-7.10.4.tgz?cache=0&sync_timestamp=1593522970831&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-private-methods%2Fdownload%2F%40babel%2Fplugin-proposal-private-methods-7.10.4.tgz", - "integrity": "sha1-sWDZcrj9ulx9ERoUX8jEIfwqaQk=", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-unicode-property-regex/download/@babel/plugin-proposal-unicode-property-regex-7.10.4.tgz?cache=0&sync_timestamp=1593522975170&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-unicode-property-regex%2Fdownload%2F%40babel%2Fplugin-proposal-unicode-property-regex-7.10.4.tgz", - "integrity": "sha1-RIPNpTBBzjQTt/4vAAImZd36p10=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-async-generators/download/@babel/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha1-qYP7Gusuw/btBCohD2QOkOeG/g0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-class-properties/download/@babel/plugin-syntax-class-properties-7.10.4.tgz?cache=0&sync_timestamp=1593521086484&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-class-properties%2Fdownload%2F%40babel%2Fplugin-syntax-class-properties-7.10.4.tgz", - "integrity": "sha1-ZkTmoLqlWmH54yMfbJ7rbuRsEkw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-decorators/download/@babel/plugin-syntax-decorators-7.10.4.tgz?cache=0&sync_timestamp=1593521097781&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-decorators%2Fdownload%2F%40babel%2Fplugin-syntax-decorators-7.10.4.tgz", - "integrity": "sha1-aFMIWyxCn50yLQL1pjUBjN6yNgw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-dynamic-import/download/@babel/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha1-Yr+Ysto80h1iYVT8lu5bPLaOrLM=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-export-namespace-from/download/@babel/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha1-AolkqbqA28CUyRXEh618TnpmRlo=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-json-strings/download/@babel/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha1-AcohtmjNghjJ5kDLbdiMVBKyyWo=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-jsx/download/@babel/plugin-syntax-jsx-7.10.4.tgz", - "integrity": "sha1-Oauq48v3EMQ3PYQpSE5rohNAFmw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-logical-assignment-operators/download/@babel/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha1-ypHvRjA1MESLkGZSusLp/plB9pk=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-nullish-coalescing-operator/download/@babel/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha1-Fn7XA2iIYIH3S1w2xlqIwDtm0ak=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-numeric-separator/download/@babel/plugin-syntax-numeric-separator-7.10.4.tgz?cache=0&sync_timestamp=1593521788128&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-numeric-separator%2Fdownload%2F%40babel%2Fplugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha1-ubBws+M1cM2f0Hun+pHA3Te5r5c=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-object-rest-spread/download/@babel/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha1-YOIl7cvZimQDMqLnLdPmbxr1WHE=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-optional-catch-binding/download/@babel/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha1-YRGiZbz7Ag6579D9/X0mQCue1sE=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-optional-chaining/download/@babel/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha1-T2nCq5UWfgGAzVM2YT+MV4j31Io=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-top-level-await/download/@babel/plugin-syntax-top-level-await-7.10.4.tgz", - "integrity": "sha1-S764kXtU/PdoNk4KgfVg4zo+9X0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-arrow-functions/download/@babel/plugin-transform-arrow-functions-7.10.4.tgz?cache=0&sync_timestamp=1593521290488&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-arrow-functions%2Fdownload%2F%40babel%2Fplugin-transform-arrow-functions-7.10.4.tgz", - "integrity": "sha1-4ilg135pfHT0HFAdRNc9v4pqZM0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-async-to-generator/download/@babel/plugin-transform-async-to-generator-7.10.4.tgz?cache=0&sync_timestamp=1593522968362&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-async-to-generator%2Fdownload%2F%40babel%2Fplugin-transform-async-to-generator-7.10.4.tgz", - "integrity": "sha1-QaUBfknrbzzak5KlHu8pQFskWjc=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-block-scoped-functions/download/@babel/plugin-transform-block-scoped-functions-7.10.4.tgz?cache=0&sync_timestamp=1593522071341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-block-scoped-functions%2Fdownload%2F%40babel%2Fplugin-transform-block-scoped-functions-7.10.4.tgz", - "integrity": "sha1-GvpZV0T3XkOpGvc7DZmOz+Trwug=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.11.1", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-block-scoping/download/@babel/plugin-transform-block-scoping-7.11.1.tgz", - "integrity": "sha1-W37+mIUr741lLAsoFEzZOp5LUhU=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-classes/download/@babel/plugin-transform-classes-7.10.4.tgz?cache=0&sync_timestamp=1593522971188&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-classes%2Fdownload%2F%40babel%2Fplugin-transform-classes-7.10.4.tgz", - "integrity": "sha1-QFE2rys+IYvEoZJiKLyRerGgrcc=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-computed-properties/download/@babel/plugin-transform-computed-properties-7.10.4.tgz?cache=0&sync_timestamp=1593521290771&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-computed-properties%2Fdownload%2F%40babel%2Fplugin-transform-computed-properties-7.10.4.tgz", - "integrity": "sha1-ne2DqBboLe0o1S1LTsvdgQzfwOs=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-destructuring/download/@babel/plugin-transform-destructuring-7.10.4.tgz?cache=0&sync_timestamp=1593521291443&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-destructuring%2Fdownload%2F%40babel%2Fplugin-transform-destructuring-7.10.4.tgz", - "integrity": "sha1-cN3Ss9G+qD0BUJ6bsl3bOnT8heU=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-dotall-regex/download/@babel/plugin-transform-dotall-regex-7.10.4.tgz?cache=0&sync_timestamp=1593522977820&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-dotall-regex%2Fdownload%2F%40babel%2Fplugin-transform-dotall-regex-7.10.4.tgz", - "integrity": "sha1-RpwgYhBcHragQOr0+sS0iAeDle4=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-duplicate-keys/download/@babel/plugin-transform-duplicate-keys-7.10.4.tgz", - "integrity": "sha1-aX5Qyf7hQ4D+hD0fMGspVhdDHkc=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-exponentiation-operator/download/@babel/plugin-transform-exponentiation-operator-7.10.4.tgz?cache=0&sync_timestamp=1593522967206&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-exponentiation-operator%2Fdownload%2F%40babel%2Fplugin-transform-exponentiation-operator-7.10.4.tgz", - "integrity": "sha1-WuM4xX+M9AAb2zVgeuZrktZlry4=", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-for-of/download/@babel/plugin-transform-for-of-7.10.4.tgz?cache=0&sync_timestamp=1593521291715&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-for-of%2Fdownload%2F%40babel%2Fplugin-transform-for-of-7.10.4.tgz", - "integrity": "sha1-wIiS6IGdOl2ykDGxFa9RHbv+uuk=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-function-name/download/@babel/plugin-transform-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593522961117&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-function-name%2Fdownload%2F%40babel%2Fplugin-transform-function-name-7.10.4.tgz", - "integrity": "sha1-akZ4gOD8ljhRS6NpERgR3b4mRLc=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-literals/download/@babel/plugin-transform-literals-7.10.4.tgz?cache=0&sync_timestamp=1593521291903&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-literals%2Fdownload%2F%40babel%2Fplugin-transform-literals-7.10.4.tgz", - "integrity": "sha1-n0K6CEEQChNfInEtDjkcRi9XHzw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-member-expression-literals/download/@babel/plugin-transform-member-expression-literals-7.10.4.tgz?cache=0&sync_timestamp=1593521293070&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-member-expression-literals%2Fdownload%2F%40babel%2Fplugin-transform-member-expression-literals-7.10.4.tgz", - "integrity": "sha1-sexE/PGVr8uNssYs2OVRyIG6+Lc=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-amd/download/@babel/plugin-transform-modules-amd-7.10.5.tgz?cache=0&sync_timestamp=1594750712546&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-amd%2Fdownload%2F%40babel%2Fplugin-transform-modules-amd-7.10.5.tgz", - "integrity": "sha1-G5zdrwXZ6Is6rTOcs+RFxPAgqbE=", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-commonjs/download/@babel/plugin-transform-modules-commonjs-7.10.4.tgz?cache=0&sync_timestamp=1593522963909&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-commonjs%2Fdownload%2F%40babel%2Fplugin-transform-modules-commonjs-7.10.4.tgz", - "integrity": "sha1-ZmZ8Pu2h6/eJbUHx8WsXEFovvKA=", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-systemjs/download/@babel/plugin-transform-modules-systemjs-7.10.5.tgz?cache=0&sync_timestamp=1594750707592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-systemjs%2Fdownload%2F%40babel%2Fplugin-transform-modules-systemjs-7.10.5.tgz", - "integrity": "sha1-YnAJnIVAZmgbrp4F+H4bnK2+jIU=", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-umd/download/@babel/plugin-transform-modules-umd-7.10.4.tgz?cache=0&sync_timestamp=1593522964232&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-umd%2Fdownload%2F%40babel%2Fplugin-transform-modules-umd-7.10.4.tgz", - "integrity": "sha1-moSB/oG4JGVLOgtl2j34nz0hg54=", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-named-capturing-groups-regex/download/@babel/plugin-transform-named-capturing-groups-regex-7.10.4.tgz?cache=0&sync_timestamp=1593522978582&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-named-capturing-groups-regex%2Fdownload%2F%40babel%2Fplugin-transform-named-capturing-groups-regex-7.10.4.tgz", - "integrity": "sha1-eLTZeIELbzvPA/njGPL8DtQa7LY=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-new-target/download/@babel/plugin-transform-new-target-7.10.4.tgz?cache=0&sync_timestamp=1593521292141&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-new-target%2Fdownload%2F%40babel%2Fplugin-transform-new-target-7.10.4.tgz", - "integrity": "sha1-kJfXU8t7Aky3OBo7LlLpUTqcaIg=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-object-super/download/@babel/plugin-transform-object-super-7.10.4.tgz?cache=0&sync_timestamp=1593522965761&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-object-super%2Fdownload%2F%40babel%2Fplugin-transform-object-super-7.10.4.tgz", - "integrity": "sha1-1xRsTROUM+emUm+IjGZ+MUoJOJQ=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-parameters/download/@babel/plugin-transform-parameters-7.10.5.tgz?cache=0&sync_timestamp=1594750687789&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-parameters%2Fdownload%2F%40babel%2Fplugin-transform-parameters-7.10.5.tgz", - "integrity": "sha1-WdM51Y0LGVBDX0BD504lEABeLEo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-property-literals/download/@babel/plugin-transform-property-literals-7.10.4.tgz?cache=0&sync_timestamp=1593521293406&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-property-literals%2Fdownload%2F%40babel%2Fplugin-transform-property-literals-7.10.4.tgz", - "integrity": "sha1-9v5UtlkDUimHhbg+3YFdIUxC48A=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-regenerator/download/@babel/plugin-transform-regenerator-7.10.4.tgz?cache=0&sync_timestamp=1593521089707&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-regenerator%2Fdownload%2F%40babel%2Fplugin-transform-regenerator-7.10.4.tgz", - "integrity": "sha1-IBXlnYOQdOdoON4hWdtCGWb9i2M=", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-reserved-words/download/@babel/plugin-transform-reserved-words-7.10.4.tgz?cache=0&sync_timestamp=1593522978219&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-reserved-words%2Fdownload%2F%40babel%2Fplugin-transform-reserved-words-7.10.4.tgz", - "integrity": "sha1-jyaCvNzvntMn4bCGFYXXAT+KVN0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-runtime/download/@babel/plugin-transform-runtime-7.11.0.tgz", - "integrity": "sha1-4n946zbxlEhjbgXDPJD9mtm4vM8=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "resolve": "^1.8.1", - "semver": "^5.5.1" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-shorthand-properties/download/@babel/plugin-transform-shorthand-properties-7.10.4.tgz?cache=0&sync_timestamp=1593521293679&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-shorthand-properties%2Fdownload%2F%40babel%2Fplugin-transform-shorthand-properties-7.10.4.tgz", - "integrity": "sha1-n9Jexc3VVbt/Rz5ebuHJce7eTdY=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-spread/download/@babel/plugin-transform-spread-7.11.0.tgz", - "integrity": "sha1-+oTTAPXk9XdS/kGm0bPFVPE/F8w=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-sticky-regex/download/@babel/plugin-transform-sticky-regex-7.10.4.tgz?cache=0&sync_timestamp=1593521295131&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-sticky-regex%2Fdownload%2F%40babel%2Fplugin-transform-sticky-regex-7.10.4.tgz", - "integrity": "sha1-jziJ7oZXWBEwop2cyR18c7fEoo0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-regex": "^7.10.4" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-template-literals/download/@babel/plugin-transform-template-literals-7.10.5.tgz?cache=0&sync_timestamp=1594750692589&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-template-literals%2Fdownload%2F%40babel%2Fplugin-transform-template-literals-7.10.5.tgz", - "integrity": "sha1-eLxdYmpmQtszEtnQ8AH152Of3ow=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-typeof-symbol/download/@babel/plugin-transform-typeof-symbol-7.10.4.tgz?cache=0&sync_timestamp=1593522969066&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-typeof-symbol%2Fdownload%2F%40babel%2Fplugin-transform-typeof-symbol-7.10.4.tgz", - "integrity": "sha1-lQnxp+7DHE7b/+E3wWzDP/C8W/w=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-unicode-escapes/download/@babel/plugin-transform-unicode-escapes-7.10.4.tgz?cache=0&sync_timestamp=1593522967875&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-unicode-escapes%2Fdownload%2F%40babel%2Fplugin-transform-unicode-escapes-7.10.4.tgz", - "integrity": "sha1-/q5SM5HHZR3awRXa4KnQaFeJIAc=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-unicode-regex/download/@babel/plugin-transform-unicode-regex-7.10.4.tgz?cache=0&sync_timestamp=1593522975515&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-unicode-regex%2Fdownload%2F%40babel%2Fplugin-transform-unicode-regex-7.10.4.tgz", - "integrity": "sha1-5W1x+SgvrG2wnIJ0IFVXbV5tgKg=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/preset-env": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/preset-env/download/@babel/preset-env-7.11.0.tgz", - "integrity": "sha1-hg7jjyzhetYEgMICG6lok5Pvt5Y=", - "dev": true, - "requires": { - "@babel/compat-data": "^7.11.0", - "@babel/helper-compilation-targets": "^7.10.4", - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-proposal-async-generator-functions": "^7.10.4", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-dynamic-import": "^7.10.4", - "@babel/plugin-proposal-export-namespace-from": "^7.10.4", - "@babel/plugin-proposal-json-strings": "^7.10.4", - "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", - "@babel/plugin-proposal-numeric-separator": "^7.10.4", - "@babel/plugin-proposal-object-rest-spread": "^7.11.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", - "@babel/plugin-proposal-optional-chaining": "^7.11.0", - "@babel/plugin-proposal-private-methods": "^7.10.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.10.4", - "@babel/plugin-transform-arrow-functions": "^7.10.4", - "@babel/plugin-transform-async-to-generator": "^7.10.4", - "@babel/plugin-transform-block-scoped-functions": "^7.10.4", - "@babel/plugin-transform-block-scoping": "^7.10.4", - "@babel/plugin-transform-classes": "^7.10.4", - "@babel/plugin-transform-computed-properties": "^7.10.4", - "@babel/plugin-transform-destructuring": "^7.10.4", - "@babel/plugin-transform-dotall-regex": "^7.10.4", - "@babel/plugin-transform-duplicate-keys": "^7.10.4", - "@babel/plugin-transform-exponentiation-operator": "^7.10.4", - "@babel/plugin-transform-for-of": "^7.10.4", - "@babel/plugin-transform-function-name": "^7.10.4", - "@babel/plugin-transform-literals": "^7.10.4", - "@babel/plugin-transform-member-expression-literals": "^7.10.4", - "@babel/plugin-transform-modules-amd": "^7.10.4", - "@babel/plugin-transform-modules-commonjs": "^7.10.4", - "@babel/plugin-transform-modules-systemjs": "^7.10.4", - "@babel/plugin-transform-modules-umd": "^7.10.4", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", - "@babel/plugin-transform-new-target": "^7.10.4", - "@babel/plugin-transform-object-super": "^7.10.4", - "@babel/plugin-transform-parameters": "^7.10.4", - "@babel/plugin-transform-property-literals": "^7.10.4", - "@babel/plugin-transform-regenerator": "^7.10.4", - "@babel/plugin-transform-reserved-words": "^7.10.4", - "@babel/plugin-transform-shorthand-properties": "^7.10.4", - "@babel/plugin-transform-spread": "^7.11.0", - "@babel/plugin-transform-sticky-regex": "^7.10.4", - "@babel/plugin-transform-template-literals": "^7.10.4", - "@babel/plugin-transform-typeof-symbol": "^7.10.4", - "@babel/plugin-transform-unicode-escapes": "^7.10.4", - "@babel/plugin-transform-unicode-regex": "^7.10.4", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.11.0", - "browserslist": "^4.12.0", - "core-js-compat": "^3.6.2", - "invariant": "^2.2.2", - "levenary": "^1.1.1", - "semver": "^5.5.0" - } - }, - "@babel/preset-modules": { - "version": "0.1.3", - "resolved": "https://registry.npm.taobao.org/@babel/preset-modules/download/@babel/preset-modules-0.1.3.tgz", - "integrity": "sha1-EyQrU7XvjIg8PPfd3VWzbOgPvHI=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/runtime": { - "version": "7.11.2", - "resolved": "https://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.11.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.11.2.tgz", - "integrity": "sha1-9UnBPHVMxAuHZEufqfCaapX+BzY=", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.11.0.tgz", - "integrity": "sha1-m5ls4bmPU/fD5BdRFWBdVu0H3SQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.11.0", - "@babel/types": "^7.11.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.11.0.tgz", - "integrity": "sha1-Kua/G6mujDxDgk5YYSaYcbIG6Q0=", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "@hapi/address": { - "version": "2.1.4", - "resolved": "https://registry.npm.taobao.org/@hapi/address/download/@hapi/address-2.1.4.tgz?cache=0&sync_timestamp=1593993895205&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Faddress%2Fdownload%2F%40hapi%2Faddress-2.1.4.tgz", - "integrity": "sha1-XWftQ/P9QaadS5/3tW58DR0KgeU=", - "dev": true - }, - "@hapi/bourne": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/@hapi/bourne/download/@hapi/bourne-1.3.2.tgz?cache=0&sync_timestamp=1593915150444&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Fbourne%2Fdownload%2F%40hapi%2Fbourne-1.3.2.tgz", - "integrity": "sha1-CnCVreoGckPOMoPhtWuKj0U7JCo=", - "dev": true - }, - "@hapi/hoek": { - "version": "8.5.1", - "resolved": "https://registry.npm.taobao.org/@hapi/hoek/download/@hapi/hoek-8.5.1.tgz?cache=0&sync_timestamp=1596229985980&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Fhoek%2Fdownload%2F%40hapi%2Fhoek-8.5.1.tgz", - "integrity": "sha1-/elgZMpEbeyMVajC8TCVewcMbgY=", - "dev": true - }, - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npm.taobao.org/@hapi/joi/download/@hapi/joi-15.1.1.tgz", - "integrity": "sha1-xnW4pxKW8Cgz+NbSQ7NMV7jOGdc=", - "dev": true, - "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" - } - }, - "@hapi/topo": { - "version": "3.1.6", - "resolved": "https://registry.npm.taobao.org/@hapi/topo/download/@hapi/topo-3.1.6.tgz?cache=0&sync_timestamp=1593916080558&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Ftopo%2Fdownload%2F%40hapi%2Ftopo-3.1.6.tgz", - "integrity": "sha1-aNk1+j6uf91asNf5U/MgXYsr/Ck=", - "dev": true, - "requires": { - "@hapi/hoek": "^8.3.0" - } - }, - "@intervolga/optimize-cssnano-plugin": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/@intervolga/optimize-cssnano-plugin/download/@intervolga/optimize-cssnano-plugin-1.0.6.tgz", - "integrity": "sha1-vnx4RhKLiPapsdEmGgrQbrXA/fg=", - "dev": true, - "requires": { - "cssnano": "^4.0.0", - "cssnano-preset-default": "^4.0.0", - "postcss": "^7.0.0" - } - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/@mrmlnc/readdir-enhanced/download/@mrmlnc/readdir-enhanced-2.2.1.tgz", - "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/@nodelib/fs.stat/download/@nodelib/fs.stat-1.1.3.tgz", - "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=", - "dev": true - }, - "@soda/friendly-errors-webpack-plugin": { - "version": "1.7.1", - "resolved": "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.7.1.tgz", - "integrity": "sha1-cG9kvLSouWQrSK46zkRMcDNNYV0=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "error-stack-parser": "^2.0.0", - "string-width": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "@soda/get-current-script": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/@soda/get-current-script/download/@soda/get-current-script-1.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40soda%2Fget-current-script%2Fdownload%2F%40soda%2Fget-current-script-1.0.2.tgz", - "integrity": "sha1-pTUV2yXYA4N0OBtzryC7Ty5QjYc=", - "dev": true - }, - "@types/anymatch": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/@types/anymatch/download/@types/anymatch-1.3.1.tgz", - "integrity": "sha1-M2utwb7sudrMOL6izzKt9ieoQho=", - "dev": true - }, - "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npm.taobao.org/@types/body-parser/download/@types/body-parser-1.19.0.tgz", - "integrity": "sha1-BoWzxH6zAG/+0RfN1VFkth+AU48=", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/@types/color-name/download/@types/color-name-1.1.1.tgz", - "integrity": "sha1-HBJhu+qhCoBVu8XYq4S3sq/IRqA=", - "dev": true - }, - "@types/connect": { - "version": "3.4.33", - "resolved": "https://registry.npm.taobao.org/@types/connect/download/@types/connect-3.4.33.tgz?cache=0&sync_timestamp=1596837850490&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fconnect%2Fdownload%2F%40types%2Fconnect-3.4.33.tgz", - "integrity": "sha1-MWEMkB7KVzuHE8MzCrxua59YhUY=", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/connect-history-api-fallback": { - "version": "1.3.3", - "resolved": "https://registry.npm.taobao.org/@types/connect-history-api-fallback/download/@types/connect-history-api-fallback-1.3.3.tgz", - "integrity": "sha1-R3K3m4tTGF8PTJ3qsJI2uvdu47Q=", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "@types/express": { - "version": "4.17.7", - "resolved": "https://registry.npm.taobao.org/@types/express/download/@types/express-4.17.7.tgz", - "integrity": "sha1-QgRb5kdWNtmAE2nNRBjvZc2w3Vk=", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "*", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.9", - "resolved": "https://registry.npm.taobao.org/@types/express-serve-static-core/download/@types/express-serve-static-core-4.17.9.tgz", - "integrity": "sha1-LXs03P0l7GY8JchddmCPiySWZ/E=", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npm.taobao.org/@types/glob/download/@types/glob-7.1.3.tgz?cache=0&sync_timestamp=1596838206290&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fglob%2Fdownload%2F%40types%2Fglob-7.1.3.tgz", - "integrity": "sha1-5rqA82t9qtLGhazZJmOC5omFwYM=", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/http-proxy": { - "version": "1.17.4", - "resolved": "https://registry.npm.taobao.org/@types/http-proxy/download/@types/http-proxy-1.17.4.tgz?cache=0&sync_timestamp=1596839386031&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fhttp-proxy%2Fdownload%2F%40types%2Fhttp-proxy-1.17.4.tgz", - "integrity": "sha1-58kuPb4+E6p5lED/QubToXqdBFs=", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/http-proxy-middleware": { - "version": "0.19.3", - "resolved": "https://registry.npm.taobao.org/@types/http-proxy-middleware/download/@types/http-proxy-middleware-0.19.3.tgz?cache=0&sync_timestamp=1596839386511&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fhttp-proxy-middleware%2Fdownload%2F%40types%2Fhttp-proxy-middleware-0.19.3.tgz", - "integrity": "sha1-suuW+8D5rHJQtdnExTqt4ElJfQM=", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/http-proxy": "*", - "@types/node": "*" - } - }, - "@types/json-schema": { - "version": "7.0.5", - "resolved": "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.5.tgz?cache=0&sync_timestamp=1596838729190&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.5.tgz", - "integrity": "sha1-3M5EMOZLRDuolF8CkPtWStW6xt0=", - "dev": true - }, - "@types/mime": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/@types/mime/download/@types/mime-2.0.3.tgz", - "integrity": "sha1-yJO3NyHbc2mZQ7/DZTsd63+qSjo=", - "dev": true - }, - "@types/mini-css-extract-plugin": { - "version": "0.9.1", - "resolved": "https://registry.npm.taobao.org/@types/mini-css-extract-plugin/download/@types/mini-css-extract-plugin-0.9.1.tgz?cache=0&sync_timestamp=1596839014743&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fmini-css-extract-plugin%2Fdownload%2F%40types%2Fmini-css-extract-plugin-0.9.1.tgz", - "integrity": "sha1-1L3eUZcyb8oDnUGPS92gPcdNxFE=", - "dev": true, - "optional": true, - "requires": { - "@types/webpack": "*" - } - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/@types/minimatch/download/@types/minimatch-3.0.3.tgz?cache=0&sync_timestamp=1596839141589&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fminimatch%2Fdownload%2F%40types%2Fminimatch-3.0.3.tgz", - "integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=", - "dev": true - }, - "@types/minimist": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/@types/minimist/download/@types/minimist-1.2.0.tgz", - "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", - "dev": true - }, - "@types/node": { - "version": "14.6.0", - "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-14.6.0.tgz?cache=0&sync_timestamp=1597674929436&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.6.0.tgz", - "integrity": "sha1-fUQRv1FXM5M318/4ZNn/RfF3tJk=", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/@types/normalize-package-data/download/@types/normalize-package-data-2.4.0.tgz?cache=0&sync_timestamp=1596839391651&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnormalize-package-data%2Fdownload%2F%40types%2Fnormalize-package-data-2.4.0.tgz", - "integrity": "sha1-5IbQ2XOW15vu3QpuM/RTT/a0lz4=", - "dev": true - }, - "@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npm.taobao.org/@types/q/download/@types/q-1.5.4.tgz", - "integrity": "sha1-FZJUFOCtLNdlv+9YhC9+JqesyyQ=", - "dev": true - }, - "@types/qs": { - "version": "6.9.4", - "resolved": "https://registry.npm.taobao.org/@types/qs/download/@types/qs-6.9.4.tgz", - "integrity": "sha1-pZ6FHBuhbAUT6hI4MN1jmgoVy2o=", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.3", - "resolved": "https://registry.npm.taobao.org/@types/range-parser/download/@types/range-parser-1.2.3.tgz", - "integrity": "sha1-fuMwunyq+5gJC+zoal7kQRWQTCw=", - "dev": true - }, - "@types/serve-static": { - "version": "1.13.5", - "resolved": "https://registry.npm.taobao.org/@types/serve-static/download/@types/serve-static-1.13.5.tgz?cache=0&sync_timestamp=1596840339942&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fserve-static%2Fdownload%2F%40types%2Fserve-static-1.13.5.tgz", - "integrity": "sha1-PSXZQaGEFdOrCS3vhG4TWgi7z1M=", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/mime": "*" - } - }, - "@types/source-list-map": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/@types/source-list-map/download/@types/source-list-map-0.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fsource-list-map%2Fdownload%2F%40types%2Fsource-list-map-0.1.2.tgz", - "integrity": "sha1-AHiDYGP/rxdBI0m7o2QIfgrALsk=", - "dev": true - }, - "@types/tapable": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.6.tgz", - "integrity": "sha1-qcpLcKGLJwzLK8Cqr+/R1Ia36nQ=", - "dev": true - }, - "@types/uglify-js": { - "version": "3.9.3", - "resolved": "https://registry.npm.taobao.org/@types/uglify-js/download/@types/uglify-js-3.9.3.tgz?cache=0&sync_timestamp=1596841575547&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fuglify-js%2Fdownload%2F%40types%2Fuglify-js-3.9.3.tgz", - "integrity": "sha1-2U7WCOKVvFQkyWAOa4VlQHtrS2s=", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "@types/webpack": { - "version": "4.41.21", - "resolved": "https://registry.npm.taobao.org/@types/webpack/download/@types/webpack-4.41.21.tgz?cache=0&sync_timestamp=1596841577093&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack%2Fdownload%2F%40types%2Fwebpack-4.41.21.tgz", - "integrity": "sha1-zGhbMywz8VO7L1/B+jrIretZLe4=", - "dev": true, - "requires": { - "@types/anymatch": "*", - "@types/node": "*", - "@types/tapable": "*", - "@types/uglify-js": "*", - "@types/webpack-sources": "*", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "@types/webpack-dev-server": { - "version": "3.11.0", - "resolved": "https://registry.npm.taobao.org/@types/webpack-dev-server/download/@types/webpack-dev-server-3.11.0.tgz?cache=0&sync_timestamp=1596841577349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack-dev-server%2Fdownload%2F%40types%2Fwebpack-dev-server-3.11.0.tgz", - "integrity": "sha1-vMO4Xn3GrC2yUzBhBRPyIowvz7I=", - "dev": true, - "requires": { - "@types/connect-history-api-fallback": "*", - "@types/express": "*", - "@types/http-proxy-middleware": "*", - "@types/serve-static": "*", - "@types/webpack": "*" - } - }, - "@types/webpack-sources": { - "version": "1.4.2", - "resolved": "https://registry.npm.taobao.org/@types/webpack-sources/download/@types/webpack-sources-1.4.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack-sources%2Fdownload%2F%40types%2Fwebpack-sources-1.4.2.tgz", - "integrity": "sha1-XT1N6gQAineakBNf+W+1wMnmKSw=", - "dev": true, - "requires": { - "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.7.3.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.7.3.tgz", - "integrity": "sha1-UwL4FpAxc1ImVECS5kmB91F1A4M=", - "dev": true - } - } - }, - "@vue/babel-helper-vue-jsx-merge-props": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.0.0.tgz?cache=0&sync_timestamp=1596768129236&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-helper-vue-jsx-merge-props%2Fdownload%2F%40vue%2Fbabel-helper-vue-jsx-merge-props-1.0.0.tgz", - "integrity": "sha1-BI/leZWNpAj7eosqPsBQtQpmEEA=", - "dev": true - }, - "@vue/babel-plugin-transform-vue-jsx": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-plugin-transform-vue-jsx/download/@vue/babel-plugin-transform-vue-jsx-1.1.2.tgz", - "integrity": "sha1-wKPm78Ai515CR7RIqPxrhvA+kcA=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "html-tags": "^2.0.0", - "lodash.kebabcase": "^4.1.1", - "svg-tags": "^1.0.0" - }, - "dependencies": { - "html-tags": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-2.0.0.tgz", - "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", - "dev": true - } - } - }, - "@vue/babel-preset-app": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/babel-preset-app/download/@vue/babel-preset-app-4.5.4.tgz", - "integrity": "sha1-uxZOirVWc8Vh5ug1EWMe2hnv1+Q=", - "dev": true, - "requires": { - "@ant-design-vue/babel-plugin-jsx": "^1.0.0-0", - "@babel/core": "^7.11.0", - "@babel/helper-compilation-targets": "^7.9.6", - "@babel/helper-module-imports": "^7.8.3", - "@babel/plugin-proposal-class-properties": "^7.8.3", - "@babel/plugin-proposal-decorators": "^7.8.3", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-jsx": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.11.0", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.0", - "@vue/babel-preset-jsx": "^1.1.2", - "babel-plugin-dynamic-import-node": "^2.3.3", - "core-js": "^3.6.5", - "core-js-compat": "^3.6.5", - "semver": "^6.1.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "@vue/babel-preset-jsx": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-preset-jsx/download/@vue/babel-preset-jsx-1.1.2.tgz", - "integrity": "sha1-LhaetMIE6jfKZsLqhaiAv8mdTyA=", - "dev": true, - "requires": { - "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", - "@vue/babel-sugar-functional-vue": "^1.1.2", - "@vue/babel-sugar-inject-h": "^1.1.2", - "@vue/babel-sugar-v-model": "^1.1.2", - "@vue/babel-sugar-v-on": "^1.1.2" - } - }, - "@vue/babel-sugar-functional-vue": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-functional-vue/download/@vue/babel-sugar-functional-vue-1.1.2.tgz", - "integrity": "sha1-9+JPugnm8e5wEEVgqICAV1VfGpo=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0" - } - }, - "@vue/babel-sugar-inject-h": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-inject-h/download/@vue/babel-sugar-inject-h-1.1.2.tgz", - "integrity": "sha1-ilJ2ttji7Rb/yAeKrZQjYnTm7fA=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0" - } - }, - "@vue/babel-sugar-v-model": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-v-model/download/@vue/babel-sugar-v-model-1.1.2.tgz", - "integrity": "sha1-H/b9G4ACI/ycsehNzrXlLXN6gZI=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", - "camelcase": "^5.0.0", - "html-tags": "^2.0.0", - "svg-tags": "^1.0.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1589682790492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", - "dev": true - }, - "html-tags": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-2.0.0.tgz", - "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", - "dev": true - } - } - }, - "@vue/babel-sugar-v-on": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-v-on/download/@vue/babel-sugar-v-on-1.1.2.tgz", - "integrity": "sha1-su+ZuPL6sJ++rSWq1w70Lhz1sTs=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", - "camelcase": "^5.0.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1589682790492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", - "dev": true - } - } - }, - "@vue/cli-overlay": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-overlay/download/@vue/cli-overlay-4.5.4.tgz?cache=0&sync_timestamp=1597717221287&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-overlay%2Fdownload%2F%40vue%2Fcli-overlay-4.5.4.tgz", - "integrity": "sha1-4H48zC5Ndw1P29Rc3ed31ZKCLBk=", - "dev": true - }, - "@vue/cli-plugin-babel": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-babel/download/@vue/cli-plugin-babel-4.5.4.tgz", - "integrity": "sha1-oBzcs9RgZGdd2I1htkCtrcyFHis=", - "dev": true, - "requires": { - "@babel/core": "^7.11.0", - "@vue/babel-preset-app": "^4.5.4", - "@vue/cli-shared-utils": "^4.5.4", - "babel-loader": "^8.1.0", - "cache-loader": "^4.1.0", - "thread-loader": "^2.1.3", - "webpack": "^4.0.0" - } - }, - "@vue/cli-plugin-eslint": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-eslint/download/@vue/cli-plugin-eslint-4.5.4.tgz", - "integrity": "sha1-Dx8wer/h5K1n3Ll2k2QJQrFfrnY=", - "dev": true, - "requires": { - "@vue/cli-shared-utils": "^4.5.4", - "eslint-loader": "^2.2.1", - "globby": "^9.2.0", - "inquirer": "^7.1.0", - "webpack": "^4.0.0", - "yorkie": "^2.0.0" - } - }, - "@vue/cli-plugin-router": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-router/download/@vue/cli-plugin-router-4.5.4.tgz", - "integrity": "sha1-BvIkCMftas7dv3MCy0eik7evQ0c=", - "dev": true, - "requires": { - "@vue/cli-shared-utils": "^4.5.4" - } - }, - "@vue/cli-plugin-vuex": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.5.4.tgz", - "integrity": "sha1-YpbjBziPYRMhF+CsAxiAE2UrDFU=", - "dev": true - }, - "@vue/cli-service": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-service/download/@vue/cli-service-4.5.4.tgz?cache=0&sync_timestamp=1597717222018&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-service%2Fdownload%2F%40vue%2Fcli-service-4.5.4.tgz", - "integrity": "sha1-+QPt9VXRB0BGJN4v7VmW2oztxSQ=", - "dev": true, - "requires": { - "@intervolga/optimize-cssnano-plugin": "^1.0.5", - "@soda/friendly-errors-webpack-plugin": "^1.7.1", - "@soda/get-current-script": "^1.0.0", - "@types/minimist": "^1.2.0", - "@types/webpack": "^4.0.0", - "@types/webpack-dev-server": "^3.11.0", - "@vue/cli-overlay": "^4.5.4", - "@vue/cli-plugin-router": "^4.5.4", - "@vue/cli-plugin-vuex": "^4.5.4", - "@vue/cli-shared-utils": "^4.5.4", - "@vue/component-compiler-utils": "^3.1.2", - "@vue/preload-webpack-plugin": "^1.1.0", - "@vue/web-component-wrapper": "^1.2.0", - "acorn": "^7.4.0", - "acorn-walk": "^7.1.1", - "address": "^1.1.2", - "autoprefixer": "^9.8.6", - "browserslist": "^4.12.0", - "cache-loader": "^4.1.0", - "case-sensitive-paths-webpack-plugin": "^2.3.0", - "cli-highlight": "^2.1.4", - "clipboardy": "^2.3.0", - "cliui": "^6.0.0", - "copy-webpack-plugin": "^5.1.1", - "css-loader": "^3.5.3", - "cssnano": "^4.1.10", - "debug": "^4.1.1", - "default-gateway": "^5.0.5", - "dotenv": "^8.2.0", - "dotenv-expand": "^5.1.0", - "file-loader": "^4.2.0", - "fs-extra": "^7.0.1", - "globby": "^9.2.0", - "hash-sum": "^2.0.0", - "html-webpack-plugin": "^3.2.0", - "launch-editor-middleware": "^2.2.1", - "lodash.defaultsdeep": "^4.6.1", - "lodash.mapvalues": "^4.6.0", - "lodash.transform": "^4.6.0", - "mini-css-extract-plugin": "^0.9.0", - "minimist": "^1.2.5", - "pnp-webpack-plugin": "^1.6.4", - "portfinder": "^1.0.26", - "postcss-loader": "^3.0.0", - "ssri": "^7.1.0", - "terser-webpack-plugin": "^2.3.6", - "thread-loader": "^2.1.3", - "url-loader": "^2.2.0", - "vue-loader": "^15.9.2", - "vue-loader-v16": "npm:vue-loader@^16.0.0-beta.3", - "vue-style-loader": "^4.1.2", - "webpack": "^4.0.0", - "webpack-bundle-analyzer": "^3.8.0", - "webpack-chain": "^6.4.0", - "webpack-dev-server": "^3.11.0", - "webpack-merge": "^4.2.2" - }, - "dependencies": { - "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-7.4.0.tgz?cache=0&sync_timestamp=1597235774928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-7.4.0.tgz", - "integrity": "sha1-4a1IbmxUUBY0xsOXxcEh2qODYHw=", - "dev": true - }, - "cacache": { - "version": "13.0.1", - "resolved": "https://registry.npm.taobao.org/cacache/download/cacache-13.0.1.tgz?cache=0&sync_timestamp=1594429684526&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcacache%2Fdownload%2Fcacache-13.0.1.tgz", - "integrity": "sha1-qAAMIWlwiQgvhSh6GuxuOCAkpxw=", - "dev": true, - "requires": { - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "minipass": "^3.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "p-map": "^3.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^2.7.1", - "ssri": "^7.0.0", - "unique-filename": "^1.1.1" - } - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-3.3.1.tgz", - "integrity": "sha1-ibM/rUpGcNqpT4Vff74x1thP6IA=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz?cache=0&sync_timestamp=1597169842138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz", - "integrity": "sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8=", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-4.2.0.tgz", - "integrity": "sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM=", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - }, - "ssri": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/ssri/download/ssri-7.1.0.tgz", - "integrity": "sha1-ksJBv23oI2W1x/tL126XVSLhKU0=", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1", - "minipass": "^3.1.1" - } - }, - "terser-webpack-plugin": { - "version": "2.3.8", - "resolved": "https://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-2.3.8.tgz?cache=0&sync_timestamp=1597229593156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-2.3.8.tgz", - "integrity": "sha1-iUdkoZsHQ/L3BOfCqEjFKDppZyQ=", - "dev": true, - "requires": { - "cacache": "^13.0.1", - "find-cache-dir": "^3.3.1", - "jest-worker": "^25.4.0", - "p-limit": "^2.3.0", - "schema-utils": "^2.6.6", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.6.12", - "webpack-sources": "^1.4.3" - } - } - } - }, - "@vue/cli-shared-utils": { - "version": "4.5.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-shared-utils/download/@vue/cli-shared-utils-4.5.4.tgz?cache=0&sync_timestamp=1597717221168&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-shared-utils%2Fdownload%2F%40vue%2Fcli-shared-utils-4.5.4.tgz", - "integrity": "sha1-7Taylx3AJlP38q1OZrvpUQ4b1BQ=", - "dev": true, - "requires": { - "@hapi/joi": "^15.0.1", - "chalk": "^2.4.2", - "execa": "^1.0.0", - "launch-editor": "^2.2.1", - "lru-cache": "^5.1.1", - "node-ipc": "^9.1.1", - "open": "^6.3.0", - "ora": "^3.4.0", - "read-pkg": "^5.1.1", - "request": "^2.88.2", - "semver": "^6.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "@vue/compiler-core": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/compiler-core/download/@vue/compiler-core-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595985153463&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcompiler-core%2Fdownload%2F%40vue%2Fcompiler-core-3.0.0-rc.5.tgz", - "integrity": "sha1-3U8YFvyuNKgbxg5YT5eZPK0oTVQ=", - "requires": { - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4", - "@vue/shared": "3.0.0-rc.5", - "estree-walker": "^2.0.1", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" - } - } - }, - "@vue/compiler-dom": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/compiler-dom/download/@vue/compiler-dom-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595985152508&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcompiler-dom%2Fdownload%2F%40vue%2Fcompiler-dom-3.0.0-rc.5.tgz", - "integrity": "sha1-g5BehgESOjZUuQ+9gHCKFlMM4ho=", - "requires": { - "@vue/compiler-core": "3.0.0-rc.5", - "@vue/shared": "3.0.0-rc.5" - } - }, - "@vue/compiler-sfc": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/compiler-sfc/download/@vue/compiler-sfc-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595985044175&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcompiler-sfc%2Fdownload%2F%40vue%2Fcompiler-sfc-3.0.0-rc.5.tgz", - "integrity": "sha1-N05Spvv4+5ruEhMCYFCg8cSW/s8=", - "dev": true, - "requires": { - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4", - "@vue/compiler-core": "3.0.0-rc.5", - "@vue/compiler-dom": "3.0.0-rc.5", - "@vue/compiler-ssr": "3.0.0-rc.5", - "@vue/shared": "3.0.0-rc.5", - "consolidate": "^0.15.1", - "estree-walker": "^2.0.1", - "hash-sum": "^2.0.0", - "lru-cache": "^5.1.1", - "magic-string": "^0.25.7", - "merge-source-map": "^1.1.0", - "postcss": "^7.0.27", - "postcss-modules": "^3.1.0", - "postcss-selector-parser": "^6.0.2", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "@vue/compiler-ssr": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/compiler-ssr/download/@vue/compiler-ssr-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595985044376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcompiler-ssr%2Fdownload%2F%40vue%2Fcompiler-ssr-3.0.0-rc.5.tgz", - "integrity": "sha1-h4QGxZ2v82Ls3LGZ+5Rnp2nKjeU=", - "dev": true, - "requires": { - "@vue/compiler-dom": "3.0.0-rc.5", - "@vue/shared": "3.0.0-rc.5" - } - }, - "@vue/component-compiler-utils": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/@vue/component-compiler-utils/download/@vue/component-compiler-utils-3.2.0.tgz?cache=0&sync_timestamp=1595427628913&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcomponent-compiler-utils%2Fdownload%2F%40vue%2Fcomponent-compiler-utils-3.2.0.tgz", - "integrity": "sha1-j4UYLO7Sjps8dTE95mn4MWbRHl0=", - "dev": true, - "requires": { - "consolidate": "^0.15.1", - "hash-sum": "^1.0.2", - "lru-cache": "^4.1.2", - "merge-source-map": "^1.1.0", - "postcss": "^7.0.14", - "postcss-selector-parser": "^6.0.2", - "prettier": "^1.18.2", - "source-map": "~0.6.1", - "vue-template-es2015-compiler": "^1.9.0" - }, - "dependencies": { - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "@vue/preload-webpack-plugin": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/preload-webpack-plugin/download/@vue/preload-webpack-plugin-1.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fpreload-webpack-plugin%2Fdownload%2F%40vue%2Fpreload-webpack-plugin-1.1.2.tgz", - "integrity": "sha1-zrkktOyzucQ4ccekKaAvhCPmIas=", - "dev": true - }, - "@vue/reactivity": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/reactivity/download/@vue/reactivity-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595985154146&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Freactivity%2Fdownload%2F%40vue%2Freactivity-3.0.0-rc.5.tgz", - "integrity": "sha1-Rc/42DnXrRMLHkmSOQkAUP3s/xM=", - "requires": { - "@vue/shared": "3.0.0-rc.5" - } - }, - "@vue/runtime-core": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/runtime-core/download/@vue/runtime-core-3.0.0-rc.5.tgz", - "integrity": "sha1-3VmvOl/AidHNwFplcyDA3Bflw2I=", - "requires": { - "@vue/reactivity": "3.0.0-rc.5", - "@vue/shared": "3.0.0-rc.5" - } - }, - "@vue/runtime-dom": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/runtime-dom/download/@vue/runtime-dom-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595985153167&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fruntime-dom%2Fdownload%2F%40vue%2Fruntime-dom-3.0.0-rc.5.tgz", - "integrity": "sha1-L9daHymyOr8P/lzN7avaEXIcW1s=", - "requires": { - "@vue/runtime-core": "3.0.0-rc.5", - "@vue/shared": "3.0.0-rc.5", - "csstype": "^2.6.8" - } - }, - "@vue/shared": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/@vue/shared/download/@vue/shared-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595985152851&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fshared%2Fdownload%2F%40vue%2Fshared-3.0.0-rc.5.tgz", - "integrity": "sha1-zqI3jj43Nj3cH13RWO3JybWz//A=" - }, - "@vue/web-component-wrapper": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/@vue/web-component-wrapper/download/@vue/web-component-wrapper-1.2.0.tgz", - "integrity": "sha1-uw5G8VhafiibTuYGfcxaauYvHdE=", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/ast/download/@webassemblyjs/ast-1.9.0.tgz", - "integrity": "sha1-vYUGBLQEJFmlpBzX0zjL7Wle2WQ=", - "dev": true, - "requires": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/floating-point-hex-parser/download/@webassemblyjs/floating-point-hex-parser-1.9.0.tgz", - "integrity": "sha1-PD07Jxvd/ITesA9xNEQ4MR1S/7Q=", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-api-error/download/@webassemblyjs/helper-api-error-1.9.0.tgz", - "integrity": "sha1-ID9nbjM7lsnaLuqzzO8zxFkotqI=", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-buffer/download/@webassemblyjs/helper-buffer-1.9.0.tgz", - "integrity": "sha1-oUQtJpxf6yP8vJ73WdrDVH8p3gA=", - "dev": true - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-code-frame/download/@webassemblyjs/helper-code-frame-1.9.0.tgz", - "integrity": "sha1-ZH+Iks0gQ6gqwMjF51w28dkVnyc=", - "dev": true, - "requires": { - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-fsm/download/@webassemblyjs/helper-fsm-1.9.0.tgz", - "integrity": "sha1-wFJWtxJEIUZx9LCOwQitY7cO3bg=", - "dev": true - }, - "@webassemblyjs/helper-module-context": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-module-context/download/@webassemblyjs/helper-module-context-1.9.0.tgz", - "integrity": "sha1-JdiIS3aDmHGgimxvgGw5ee9xLwc=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-wasm-bytecode/download/@webassemblyjs/helper-wasm-bytecode-1.9.0.tgz", - "integrity": "sha1-T+2L6sm4wU+MWLcNEk1UndH+V5A=", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-wasm-section/download/@webassemblyjs/helper-wasm-section-1.9.0.tgz", - "integrity": "sha1-WkE41aYpK6GLBMWuSXF+QWeWU0Y=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/ieee754/download/@webassemblyjs/ieee754-1.9.0.tgz", - "integrity": "sha1-Fceg+6roP7JhQ7us9tbfFwKtOeQ=", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/leb128/download/@webassemblyjs/leb128-1.9.0.tgz", - "integrity": "sha1-8Zygt2ptxVYjoJz/p2noOPoeHJU=", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/utf8/download/@webassemblyjs/utf8-1.9.0.tgz", - "integrity": "sha1-BNM7Y2945qaBMifoJAL3Y3tiKas=", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-edit/download/@webassemblyjs/wasm-edit-1.9.0.tgz", - "integrity": "sha1-P+bXnT8PkiGDqoYALELdJWz+6c8=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/helper-wasm-section": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-opt": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-gen/download/@webassemblyjs/wasm-gen-1.9.0.tgz", - "integrity": "sha1-ULxw7Gje2OJ2OwGhQYv0NJGnpJw=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-opt/download/@webassemblyjs/wasm-opt-1.9.0.tgz", - "integrity": "sha1-IhEYHlsxMmRDzIES658LkChyGmE=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-parser/download/@webassemblyjs/wasm-parser-1.9.0.tgz", - "integrity": "sha1-nUjkSCbfSmWYKUqmyHRp1kL/9l4=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wast-parser/download/@webassemblyjs/wast-parser-1.9.0.tgz", - "integrity": "sha1-MDERXXmsW9JhVWzsw/qQo+9FGRQ=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/floating-point-hex-parser": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-code-frame": "1.9.0", - "@webassemblyjs/helper-fsm": "1.9.0", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wast-printer/download/@webassemblyjs/wast-printer-1.9.0.tgz", - "integrity": "sha1-STXVTIX+9jewDOn1I3dFHQDUeJk=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/@xtuc/ieee754/download/@xtuc/ieee754-1.2.0.tgz", - "integrity": "sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A=", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/@xtuc/long/download/@xtuc/long-4.2.2.tgz", - "integrity": "sha1-0pHGpOl5ibXGHZrPOWrk/hM6cY0=", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", - "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-6.4.1.tgz?cache=0&sync_timestamp=1597235774928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-6.4.1.tgz", - "integrity": "sha1-Ux5Yuj9RudrLmmZGyk3r9bFMpHQ=", - "dev": true - }, - "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.2.0.tgz?cache=0&sync_timestamp=1589684116279&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-jsx%2Fdownload%2Facorn-jsx-5.2.0.tgz", - "integrity": "sha1-TGYGkXPW/daO2FI5/CViJhgrLr4=", - "dev": true - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npm.taobao.org/acorn-walk/download/acorn-walk-7.2.0.tgz?cache=0&sync_timestamp=1597235855275&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-walk%2Fdownload%2Facorn-walk-7.2.0.tgz", - "integrity": "sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w=", - "dev": true - }, - "address": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/address/download/address-1.1.2.tgz", - "integrity": "sha1-vxEWycdYxRt6kz0pa3LCIe2UKLY=", - "dev": true - }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/aggregate-error/download/aggregate-error-3.0.1.tgz", - "integrity": "sha1-2y/nJG5Tb0DZtUQqOeEX191qJOA=", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.4.tgz?cache=0&sync_timestamp=1597480759610&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.4.tgz", - "integrity": "sha1-BhT6zEUiEn+nE0Rca/0+vTduIjQ=", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/ajv-errors/download/ajv-errors-1.0.1.tgz", - "integrity": "sha1-81mGrOuRr63sQQL72FAUlQzvpk0=", - "dev": true - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz?cache=0&sync_timestamp=1595907068314&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.5.2.tgz", - "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0=", - "dev": true - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz", - "integrity": "sha1-46PaS/uubIapwoViXeEkojQCb78=", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-4.3.1.tgz", - "integrity": "sha1-pcR8xDGB8fOP/XB2g3cA05VSKmE=", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npm.taobao.org/type-fest/download/type-fest-0.11.0.tgz", - "integrity": "sha1-l6vwhyMQ/tiKXEZrJWgVdhReM/E=", - "dev": true - } - } - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npm.taobao.org/ansi-html/download/ansi-html-0.0.7.tgz?cache=0&sync_timestamp=1589682753624&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-html%2Fdownload%2Fansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "dev": true - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz?cache=0&sync_timestamp=1589682733115&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fany-promise%2Fdownload%2Fany-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.1.tgz", - "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", - "dev": true, - "optional": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/aproba/download/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", - "dev": true - }, - "arch": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/arch/download/arch-2.1.2.tgz", - "integrity": "sha1-DFK75zRLtPomDEQ9LLrZwA/y8L8=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz?cache=0&sync_timestamp=1597414329190&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fargparse%2Fdownload%2Fargparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/arr-diff/download/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/arr-flatten/download/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/arr-union/download/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/array-uniq/download/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz", - "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npm.taobao.org/asn1.js/download/asn1.js-5.4.1.tgz", - "integrity": "sha1-EamAuE67kXgc41sP3C7ilON4Pwc=", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/assert/download/assert-1.5.0.tgz", - "integrity": "sha1-VcEJqvbgrv2z3EtxJAxwv1dLGOs=", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npm.taobao.org/util/download/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/assign-symbols/download/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/astral-regex/download/astral-regex-1.0.0.tgz", - "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", - "dev": true - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npm.taobao.org/async/download/async-2.6.3.tgz", - "integrity": "sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/async-each/download/async-each-1.0.3.tgz", - "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.1.tgz", - "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/atob/download/atob-2.1.2.tgz", - "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", - "dev": true - }, - "autoprefixer": { - "version": "9.8.6", - "resolved": "https://registry.npm.taobao.org/autoprefixer/download/autoprefixer-9.8.6.tgz?cache=0&sync_timestamp=1596143120138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fautoprefixer%2Fdownload%2Fautoprefixer-9.8.6.tgz", - "integrity": "sha1-O3NZTKG/kmYyDFrPFYjXTep0IQ8=", - "dev": true, - "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "colorette": "^1.2.1", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - } - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz?cache=0&sync_timestamp=1589682812085&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws-sign2%2Fdownload%2Faws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.10.1", - "resolved": "https://registry.npm.taobao.org/aws4/download/aws4-1.10.1.tgz?cache=0&sync_timestamp=1597236947743&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws4%2Fdownload%2Faws4-1.10.1.tgz", - "integrity": "sha1-4eguTz6Zniz9YbFhKA0WoRH4ZCg=", - "dev": true - }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz", - "integrity": "sha1-aWjlaKkQt4+zd5zdi2rC9HmUMjI=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - } - }, - "babel-loader": { - "version": "8.1.0", - "resolved": "https://registry.npm.taobao.org/babel-loader/download/babel-loader-8.1.0.tgz", - "integrity": "sha1-xhHVESvVIJq+i5+oTD5NolJ18cM=", - "dev": true, - "requires": { - "find-cache-dir": "^2.1.0", - "loader-utils": "^1.4.0", - "mkdirp": "^0.5.3", - "pify": "^4.0.1", - "schema-utils": "^2.6.5" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npm.taobao.org/babel-plugin-dynamic-import-node/download/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha1-hP2hnJduxcbe/vV/lCez3vZuF6M=", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npm.taobao.org/base/download/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/base64-js/download/base64-js-1.3.1.tgz", - "integrity": "sha1-WOzoy3XdB+ce0IxzarxfrE2/jfE=", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/batch/download/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz?cache=0&sync_timestamp=1589682746075&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbcrypt-pbkdf%2Fdownload%2Fbcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bfj": { - "version": "6.1.2", - "resolved": "https://registry.npm.taobao.org/bfj/download/bfj-6.1.2.tgz", - "integrity": "sha1-MlyGGoIryzWKQceKM7jm4ght3n8=", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "check-types": "^8.0.3", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz", - "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=", - "dev": true - }, - "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-2.1.0.tgz", - "integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk=", - "dev": true, - "optional": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/bindings/download/bindings-1.5.0.tgz?cache=0&sync_timestamp=1589682780212&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbindings%2Fdownload%2Fbindings-1.5.0.tgz", - "integrity": "sha1-EDU8npRTNLwFEabZCzj7x8nFBN8=", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npm.taobao.org/bluebird/download/bluebird-3.7.2.tgz?cache=0&sync_timestamp=1589682744631&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbluebird%2Fdownload%2Fbluebird-3.7.2.tgz", - "integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=", - "dev": true - }, - "bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-5.1.3.tgz", - "integrity": "sha1-vsoAVAj2Quvr6oCwQrTRjSrA7ms=", - "dev": true - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npm.taobao.org/body-parser/download/body-parser-1.19.0.tgz", - "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", - "dev": true, - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz", - "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", - "dev": true - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npm.taobao.org/bonjour/download/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - }, - "dependencies": { - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-2.1.2.tgz", - "integrity": "sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk=", - "dev": true - } - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/brorand/download/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/browserify-aes/download/browserify-aes-1.2.0.tgz", - "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/browserify-cipher/download/browserify-cipher-1.0.1.tgz", - "integrity": "sha1-jWR0wbhwv9q807z8wZNKEOlPFfA=", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/browserify-des/download/browserify-des-1.0.2.tgz", - "integrity": "sha1-OvTx9Zg5QDVy8cZiBDdfen9wPpw=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/browserify-rsa/download/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/browserify-sign/download/browserify-sign-4.2.1.tgz?cache=0&sync_timestamp=1596557839219&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrowserify-sign%2Fdownload%2Fbrowserify-sign-4.2.1.tgz", - "integrity": "sha1-6vSt1G3VS+O7OzbAzxWrvrp5VsM=", - "dev": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz?cache=0&sync_timestamp=1589682741447&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz?cache=0&sync_timestamp=1589682795646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.2.1.tgz", - "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", - "dev": true - } - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/browserify-zlib/download/browserify-zlib-0.2.0.tgz", - "integrity": "sha1-KGlFnZqjviRf6P4sofRuLn9U1z8=", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.14.0", - "resolved": "https://registry.npm.taobao.org/browserslist/download/browserslist-4.14.0.tgz?cache=0&sync_timestamp=1596756179725&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrowserslist%2Fdownload%2Fbrowserslist-4.14.0.tgz", - "integrity": "sha1-KQiVGr/k7Jhze3LzTDvO3I1DsAA=", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001111", - "electron-to-chromium": "^1.3.523", - "escalade": "^3.0.2", - "node-releases": "^1.1.60" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npm.taobao.org/buffer/download/buffer-4.9.2.tgz", - "integrity": "sha1-Iw6tNEACmIZEhBqwJEr4xEu+Pvg=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz", - "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", - "dev": true - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/buffer-indexof/download/buffer-indexof-1.1.1.tgz", - "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", - "dev": true - }, - "buffer-json": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/buffer-json/download/buffer-json-2.0.0.tgz", - "integrity": "sha1-9z4TseQvGW/i/WfQAcfXEH7dfCM=", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/buffer-xor/download/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz?cache=0&sync_timestamp=1589682741197&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbytes%2Fdownload%2Fbytes-3.1.0.tgz", - "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", - "dev": true - }, - "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npm.taobao.org/cacache/download/cacache-12.0.4.tgz?cache=0&sync_timestamp=1594429684526&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcacache%2Fdownload%2Fcacache-12.0.4.tgz", - "integrity": "sha1-ZovL0QWutfHZL+JVcOyVJcj6pAw=", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/cache-base/download/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cache-loader": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/cache-loader/download/cache-loader-4.1.0.tgz", - "integrity": "sha1-mUjK41OuwKH8ser9ojAIFuyFOH4=", - "dev": true, - "requires": { - "buffer-json": "^2.0.0", - "find-cache-dir": "^3.0.0", - "loader-utils": "^1.2.3", - "mkdirp": "^0.5.1", - "neo-async": "^2.6.1", - "schema-utils": "^2.0.0" - }, - "dependencies": { - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-3.3.1.tgz", - "integrity": "sha1-ibM/rUpGcNqpT4Vff74x1thP6IA=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz?cache=0&sync_timestamp=1597169842138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz", - "integrity": "sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8=", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-4.2.0.tgz", - "integrity": "sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM=", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/call-me-maybe/download/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/caller-callsite/download/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/caller-path/download/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - }, - "camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/camel-case/download/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, - "camelcase": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-6.0.0.tgz?cache=0&sync_timestamp=1589682790492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-6.0.0.tgz", - "integrity": "sha1-Uln3ww414njxvcKk2RIws3ytmB4=", - "dev": true - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/caniuse-api/download/caniuse-api-3.0.0.tgz", - "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001116", - "resolved": "https://registry.npm.taobao.org/caniuse-lite/download/caniuse-lite-1.0.30001116.tgz?cache=0&sync_timestamp=1597783991061&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcaniuse-lite%2Fdownload%2Fcaniuse-lite-1.0.30001116.tgz", - "integrity": "sha1-86Peo0f5KUo73EKSMJA5zIQRf7g=", - "dev": true - }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/case-sensitive-paths-webpack-plugin/download/case-sensitive-paths-webpack-plugin-2.3.0.tgz", - "integrity": "sha1-I6xhPMmoVuT4j/i7c7u16YmCXPc=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npm.taobao.org/chardet/download/chardet-0.7.0.tgz?cache=0&sync_timestamp=1594010664806&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchardet%2Fdownload%2Fchardet-0.7.0.tgz", - "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", - "dev": true - }, - "check-types": { - "version": "8.0.3", - "resolved": "https://registry.npm.taobao.org/check-types/download/check-types-8.0.3.tgz", - "integrity": "sha1-M1bMoZyIlUTy16le1JzlCKDs9VI=", - "dev": true - }, - "chokidar": { - "version": "3.4.2", - "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-3.4.2.tgz", - "integrity": "sha1-ONyOZY3sOAl0HrPve7Ckf+QkIy0=", - "dev": true, - "optional": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", - "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", - "dev": true, - "optional": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", - "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", - "dev": true, - "optional": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz", - "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", - "dev": true, - "optional": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz", - "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", - "dev": true, - "optional": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/chownr/download/chownr-1.1.4.tgz", - "integrity": "sha1-b8nXtC0ypYNZYzdmbn0ICE2izGs=", - "dev": true - }, - "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/chrome-trace-event/download/chrome-trace-event-1.0.2.tgz", - "integrity": "sha1-I0CQ7pfH1K0aLEvq4nUF3v/GCKQ=", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/ci-info/download/ci-info-1.6.0.tgz", - "integrity": "sha1-LKINu5zrMtRSSmgzAzE/AwSx5Jc=", - "dev": true - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/cipher-base/download/cipher-base-1.0.4.tgz", - "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npm.taobao.org/clean-css/download/clean-css-4.2.3.tgz", - "integrity": "sha1-UHtd59l7SO5T2ErbAWD/YhY4D3g=", - "dev": true, - "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/clean-stack/download/clean-stack-2.2.0.tgz?cache=0&sync_timestamp=1592035524745&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fclean-stack%2Fdownload%2Fclean-stack-2.2.0.tgz", - "integrity": "sha1-7oRy27Ep5yezHooQpCfe6d/kAIs=", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-highlight": { - "version": "2.1.4", - "resolved": "https://registry.npm.taobao.org/cli-highlight/download/cli-highlight-2.1.4.tgz", - "integrity": "sha1-CYy2Qs8X9CrcHBFF4H+WDsTXUis=", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "highlight.js": "^9.6.0", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^5.1.1", - "yargs": "^15.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-3.0.0.tgz", - "integrity": "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ=", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "cli-spinners": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/cli-spinners/download/cli-spinners-2.4.0.tgz?cache=0&sync_timestamp=1595080377121&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcli-spinners%2Fdownload%2Fcli-spinners-2.4.0.tgz", - "integrity": "sha1-xiVtsha4eM+6RyDnGc7Hz3JoXX8=", - "dev": true - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/cli-width/download/cli-width-3.0.0.tgz", - "integrity": "sha1-ovSEN6LKqaIkNueUvwceyeYc7fY=", - "dev": true - }, - "clipboardy": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/clipboardy/download/clipboardy-2.3.0.tgz", - "integrity": "sha1-PCkDZQxo5GqRs4iYW8J3QofbopA=", - "dev": true, - "requires": { - "arch": "^2.1.1", - "execa": "^1.0.0", - "is-wsl": "^2.1.1" - }, - "dependencies": { - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/is-wsl/download/is-wsl-2.2.0.tgz", - "integrity": "sha1-dKTHbnfKn9P5MvKQwX6jJs0VcnE=", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - } - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-6.0.0.tgz?cache=0&sync_timestamp=1597608006561&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-6.0.0.tgz", - "integrity": "sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE=", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/clone/download/clone-1.0.4.tgz?cache=0&sync_timestamp=1589682821772&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fclone%2Fdownload%2Fclone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/coa/download/coa-2.0.2.tgz", - "integrity": "sha1-Q/bCEVG07yv1cYfbDXPeIp4+fsM=", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/color/download/color-3.1.2.tgz", - "integrity": "sha1-aBSOf4XUGtdknF+oyBBvCY0inhA=", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-string": { - "version": "1.5.3", - "resolved": "https://registry.npm.taobao.org/color-string/download/color-string-1.5.3.tgz", - "integrity": "sha1-ybvF8BtYtUkvPWhXRZy2WQziBMw=", - "dev": true, - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "colorette": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/colorette/download/colorette-1.2.1.tgz?cache=0&sync_timestamp=1593955763917&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolorette%2Fdownload%2Fcolorette-1.2.1.tgz", - "integrity": "sha1-TQuSEyXBT6+SYzCGpTbbbolWSxs=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz", - "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz", - "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz", - "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npm.taobao.org/compressible/download/compressible-2.0.18.tgz", - "integrity": "sha1-r1PMprBw1MPAdQ+9dyhqbXzEb7o=", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npm.taobao.org/compression/download/compression-1.7.4.tgz", - "integrity": "sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48=", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz?cache=0&sync_timestamp=1589682741197&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbytes%2Fdownload%2Fbytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.2.tgz?cache=0&sync_timestamp=1589682751334&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconcat-stream%2Fdownload%2Fconcat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/connect-history-api-fallback/download/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha1-izIIk1kwjRERFdgcrT/Oq4iPl7w=", - "dev": true - }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/console-browserify/download/console-browserify-1.2.0.tgz", - "integrity": "sha1-ZwY871fOts9Jk6KrOlWECujEkzY=", - "dev": true - }, - "consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npm.taobao.org/consolidate/download/consolidate-0.15.1.tgz", - "integrity": "sha1-IasEMjXHGgfUXZqtmFk7DbpWurc=", - "dev": true, - "requires": { - "bluebird": "^3.1.1" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/constants-browserify/download/constants-browserify-1.0.0.tgz?cache=0&sync_timestamp=1589682802723&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconstants-browserify%2Fdownload%2Fconstants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz", - "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz?cache=0&sync_timestamp=1589682764242&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconvert-source-map%2Fdownload%2Fconvert-source-map-1.7.0.tgz", - "integrity": "sha1-F6LLiC1/d9NJBYXizmxSRCSjpEI=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/cookie/download/cookie-0.4.0.tgz", - "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/copy-concurrently/download/copy-concurrently-1.0.5.tgz", - "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-webpack-plugin": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/copy-webpack-plugin/download/copy-webpack-plugin-5.1.1.tgz", - "integrity": "sha1-VIGgPeoRI9iKmIxv+LeCRyFPC4g=", - "dev": true, - "requires": { - "cacache": "^12.0.3", - "find-cache-dir": "^2.1.0", - "glob-parent": "^3.1.0", - "globby": "^7.1.1", - "is-glob": "^4.0.1", - "loader-utils": "^1.2.3", - "minimatch": "^3.0.4", - "normalize-path": "^3.0.0", - "p-limit": "^2.2.1", - "schema-utils": "^1.0.0", - "serialize-javascript": "^2.1.2", - "webpack-log": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "globby": { - "version": "7.1.1", - "resolved": "https://registry.npm.taobao.org/globby/download/globby-7.1.1.tgz?cache=0&sync_timestamp=1591083812416&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-7.1.1.tgz", - "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-3.3.10.tgz", - "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "serialize-javascript": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-2.1.2.tgz", - "integrity": "sha1-7OxTsOAxe9yV73arcHS3OEeF+mE=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/slash/download/slash-1.0.0.tgz?cache=0&sync_timestamp=1589682715547&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslash%2Fdownload%2Fslash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - } - } - }, - "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-3.6.5.tgz?cache=0&sync_timestamp=1589682726446&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.6.5.tgz", - "integrity": "sha1-c5XcJzrzf7LlDpvT2f6EEoUjHRo=" - }, - "core-js-compat": { - "version": "3.6.5", - "resolved": "https://registry.npm.taobao.org/core-js-compat/download/core-js-compat-3.6.5.tgz", - "integrity": "sha1-KlHZpOJd/W5pAlGqgfmePAVIHxw=", - "dev": true, - "requires": { - "browserslist": "^4.8.5", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.0.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.0.0.tgz", - "integrity": "sha1-XzyjV2HkfgWyBsba/yz4FPAxa44=", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-5.2.1.tgz?cache=0&sync_timestamp=1596310819353&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcosmiconfig%2Fdownload%2Fcosmiconfig-5.2.1.tgz", - "integrity": "sha1-BA9yaAnFked6F8CjYmykW08Wixo=", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/parse-json/download/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - } - } - }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npm.taobao.org/create-ecdh/download/create-ecdh-4.0.4.tgz", - "integrity": "sha1-1uf0v/pmc2CFoHYv06YyaE2rzE4=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/create-hash/download/create-hash-1.2.0.tgz", - "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npm.taobao.org/create-hmac/download/create-hmac-1.1.7.tgz", - "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npm.taobao.org/crypto-browserify/download/crypto-browserify-3.12.0.tgz?cache=0&sync_timestamp=1589682788096&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-browserify%2Fdownload%2Fcrypto-browserify-3.12.0.tgz", - "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npm.taobao.org/css-color-names/download/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/css-declaration-sorter/download/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha1-wZiUD2OnbX42wecQGLABchBUyyI=", - "dev": true, - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - } - }, - "css-loader": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/css-loader/download/css-loader-3.6.0.tgz", - "integrity": "sha1-Lkssfm4tJ/jI8o9hv/zS5ske9kU=", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1589682790492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/css-select/download/css-select-2.1.0.tgz", - "integrity": "sha1-ajRlM1ZjWTSoG6ymjQJVQyEF2+8=", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/css-select-base-adapter/download/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha1-Oy/0lyzDYquIVhUHqVQIoUMhNdc=", - "dev": true - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npm.taobao.org/css-tree/download/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha1-mL69YsTB2flg7DQM+fdSLjBwmiI=", - "dev": true, - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "css-what": { - "version": "3.3.0", - "resolved": "https://registry.npm.taobao.org/css-what/download/css-what-3.3.0.tgz", - "integrity": "sha1-EP7Glqns4uWRrHctdZqsq6w4zTk=", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz", - "integrity": "sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4=", - "dev": true - }, - "cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npm.taobao.org/cssnano/download/cssnano-4.1.10.tgz?cache=0&sync_timestamp=1597684732243&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcssnano%2Fdownload%2Fcssnano-4.1.10.tgz", - "integrity": "sha1-CsQfCxPRPUZUh+ERt3jULaYxuLI=", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "cssnano-preset-default": { - "version": "4.0.7", - "resolved": "https://registry.npm.taobao.org/cssnano-preset-default/download/cssnano-preset-default-4.0.7.tgz?cache=0&sync_timestamp=1597684732598&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcssnano-preset-default%2Fdownload%2Fcssnano-preset-default-4.0.7.tgz", - "integrity": "sha1-UexmLM/KD4izltzZZ5zbkxvhf3Y=", - "dev": true, - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.2", - "postcss-unique-selectors": "^4.0.1" - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/cssnano-util-get-arguments/download/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/cssnano-util-get-match/download/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/cssnano-util-raw-cache/download/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha1-sm1f1fcqEd/np4RvtMZyYPlr8oI=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/cssnano-util-same-parent/download/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha1-V0CC+yhZ0ttDOFWDXZqEVuoYu/M=", - "dev": true - }, - "csso": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/csso/download/csso-4.0.3.tgz", - "integrity": "sha1-DZmF3IUsfMKyys+74QeQFNGo6QM=", - "dev": true, - "requires": { - "css-tree": "1.0.0-alpha.39" - }, - "dependencies": { - "css-tree": { - "version": "1.0.0-alpha.39", - "resolved": "https://registry.npm.taobao.org/css-tree/download/css-tree-1.0.0-alpha.39.tgz", - "integrity": "sha1-K/8//huz93bPfu/ZHuXLp3oUnus=", - "dev": true, - "requires": { - "mdn-data": "2.0.6", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/mdn-data/download/mdn-data-2.0.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmdn-data%2Fdownload%2Fmdn-data-2.0.6.tgz", - "integrity": "sha1-hS3GD8ql2qLoz2yRicRA7T4EKXg=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "csstype": { - "version": "2.6.13", - "resolved": "https://registry.npm.taobao.org/csstype/download/csstype-2.6.13.tgz?cache=0&sync_timestamp=1596101681368&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcsstype%2Fdownload%2Fcsstype-2.6.13.tgz", - "integrity": "sha1-pokwFbkOhN1uhdDjtEKh6E8tvg8=" - }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/cyclist/download/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz?cache=0&sync_timestamp=1589682745367&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdashdash%2Fdownload%2Fdashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/deep-equal/download/deep-equal-1.1.1.tgz?cache=0&sync_timestamp=1590399968773&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeep-equal%2Fdownload%2Fdeep-equal-1.1.1.tgz", - "integrity": "sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o=", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "1.5.2", - "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz", - "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M=", - "dev": true - }, - "default-gateway": { - "version": "5.0.5", - "resolved": "https://registry.npm.taobao.org/default-gateway/download/default-gateway-5.0.5.tgz", - "integrity": "sha1-T9a9XShV05s0zFpZUFSG6ar8mxA=", - "dev": true, - "requires": { - "execa": "^3.3.0" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.3.tgz", - "integrity": "sha1-9zqFudXUHQRVUcF34ogtSshXKKY=", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/execa/download/execa-3.4.0.tgz", - "integrity": "sha1-wI7UVQ72XYWPrCaf/IVyRG8364k=", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "p-finally": "^2.0.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-5.2.0.tgz?cache=0&sync_timestamp=1597056502934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-stream%2Fdownload%2Fget-stream-5.2.0.tgz", - "integrity": "sha1-SWaheV7lrOZecGxLe+txJX1uItM=", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-stream/download/is-stream-2.0.0.tgz", - "integrity": "sha1-venDJoDW+uBBKdasnZIc54FfeOM=", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-2.1.0.tgz?cache=0&sync_timestamp=1596095644798&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmimic-fn%2Fdownload%2Fmimic-fn-2.1.0.tgz", - "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-4.0.1.tgz", - "integrity": "sha1-t+zR5e1T2o43pV4cImnguX7XSOo=", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-5.1.2.tgz?cache=0&sync_timestamp=1597005345612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fonetime%2Fdownload%2Fonetime-5.1.2.tgz", - "integrity": "sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "p-finally": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-2.0.1.tgz", - "integrity": "sha1-vW/KqcVZoJa2gIBvTWV7Pw8kBWE=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz", - "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz", - "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz", - "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz?cache=0&sync_timestamp=1589682812246&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwhich%2Fdownload%2Fwhich-2.0.2.tgz", - "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz", - "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "del": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/del/download/del-4.1.1.tgz?cache=0&sync_timestamp=1589682730753&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdel%2Fdownload%2Fdel-4.1.1.tgz", - "integrity": "sha1-no8RciLqRKMf86FWwEm5kFKp8LQ=", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "dependencies": { - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npm.taobao.org/globby/download/globby-6.1.0.tgz?cache=0&sync_timestamp=1591083812416&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/p-map/download/p-map-2.1.0.tgz", - "integrity": "sha1-MQko/u+cnsxltosXaTAYpmXOoXU=", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/des.js/download/des.js-1.0.1.tgz", - "integrity": "sha1-U4IULhvcU/hdhtU+X0qn3rkeCEM=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz", - "integrity": "sha1-AU7o+PZpxcWAI9pkuBecCDooxGw=", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npm.taobao.org/diffie-hellman/download/diffie-hellman-5.0.3.tgz", - "integrity": "sha1-QOjumPVaIUlgcUaSHGPhrl89KHU=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npm.taobao.org/dir-glob/download/dir-glob-2.2.2.tgz", - "integrity": "sha1-+gnwaUFTyJGLGLoN6vrpR2n8UMQ=", - "dev": true, - "requires": { - "path-type": "^3.0.0" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/dns-equal/download/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/dns-packet/download/dns-packet-1.3.1.tgz", - "integrity": "sha1-EqpCaYEHW+UAuRDu3NC0fdfe2lo=", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/dns-txt/download/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/doctrine/download/doctrine-3.0.0.tgz", - "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/dom-converter/download/dom-converter-0.2.0.tgz", - "integrity": "sha1-ZyGp2u4uKTaClVtq/kFncWJ7t2g=", - "dev": true, - "requires": { - "utila": "~0.4" - } - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npm.taobao.org/dom-serializer/download/dom-serializer-0.2.2.tgz", - "integrity": "sha1-GvuB9TNxcXXUeGVd68XjMtn5u1E=", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/domelementtype/download/domelementtype-2.0.1.tgz", - "integrity": "sha1-H4vf6R9aeAYydOgDtL3O326U+U0=", - "dev": true - } - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/domain-browser/download/domain-browser-1.2.0.tgz?cache=0&sync_timestamp=1597693536966&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomain-browser%2Fdownload%2Fdomain-browser-1.2.0.tgz", - "integrity": "sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto=", - "dev": true - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/domelementtype/download/domelementtype-1.3.1.tgz", - "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=", - "dev": true - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npm.taobao.org/domhandler/download/domhandler-2.4.2.tgz", - "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npm.taobao.org/domutils/download/domutils-1.7.0.tgz?cache=0&sync_timestamp=1597680509643&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomutils%2Fdownload%2Fdomutils-1.7.0.tgz", - "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/dot-prop/download/dot-prop-5.2.0.tgz?cache=0&sync_timestamp=1597574828045&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdot-prop%2Fdownload%2Fdot-prop-5.2.0.tgz", - "integrity": "sha1-w07MKVVtxF8fTCJpe29JBODMT8s=", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npm.taobao.org/dotenv/download/dotenv-8.2.0.tgz", - "integrity": "sha1-l+YZJZradQ7qPk6j4mvO6lQksWo=", - "dev": true - }, - "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/dotenv-expand/download/dotenv-expand-5.1.0.tgz", - "integrity": "sha1-P7rwIL/XlIhAcuomsel5HUWmKfA=", - "dev": true - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz", - "integrity": "sha1-Or5DrvODX4rgd9E23c4PJ2sEAOY=", - "dev": true - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npm.taobao.org/duplexify/download/duplexify-3.7.1.tgz", - "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "easy-stack": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/easy-stack/download/easy-stack-1.0.0.tgz", - "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz?cache=0&sync_timestamp=1589682745945&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fecc-jsbn%2Fdownload%2Fecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "ejs": { - "version": "2.7.4", - "resolved": "https://registry.npm.taobao.org/ejs/download/ejs-2.7.4.tgz?cache=0&sync_timestamp=1597678506855&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fejs%2Fdownload%2Fejs-2.7.4.tgz", - "integrity": "sha1-SGYSh1c9zFPjZsehrlLDoSDuybo=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.537", - "resolved": "https://registry.npm.taobao.org/electron-to-chromium/download/electron-to-chromium-1.3.537.tgz?cache=0&sync_timestamp=1597808026999&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Felectron-to-chromium%2Fdownload%2Felectron-to-chromium-1.3.537.tgz", - "integrity": "sha1-3+WV9Sg9MRPfiXFYgQ5A9sI1UoM=", - "dev": true - }, - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npm.taobao.org/elliptic/download/elliptic-6.5.3.tgz", - "integrity": "sha1-y1nrLv2vc6C9eMzXAVpirW4Pk9Y=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz", - "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz", - "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.4.tgz", - "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/enhanced-resolve/download/enhanced-resolve-4.3.0.tgz", - "integrity": "sha1-O4BvO/r8HsfeaVUe+TzKRsFwQSY=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npm.taobao.org/memory-fs/download/memory-fs-0.5.0.tgz", - "integrity": "sha1-MkwBKIuIZSlm0WHbd4OHIIRajjw=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - } - } - }, - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/entities/download/entities-2.0.3.tgz", - "integrity": "sha1-XEh+V0Krk8Fau12iJ1m4WQ7AO38=", - "dev": true - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz", - "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "error-stack-parser": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/error-stack-parser/download/error-stack-parser-2.0.6.tgz", - "integrity": "sha1-WpmnB716TFinl5AtSNgoA+3mqtg=", - "dev": true, - "requires": { - "stackframe": "^1.1.1" - } - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npm.taobao.org/es-abstract/download/es-abstract-1.17.6.tgz?cache=0&sync_timestamp=1597446082160&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fes-abstract%2Fdownload%2Fes-abstract-1.17.6.tgz", - "integrity": "sha1-kUIHFweFeyysx7iey2cDFsPi1So=", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.1.tgz", - "integrity": "sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo=", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/escalade/download/escalade-3.0.2.tgz?cache=0&sync_timestamp=1594742958135&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescalade%2Fdownload%2Fescalade-3.0.2.tgz", - "integrity": "sha1-algNcO24eIDyK0yR0NVgeN9pYsQ=", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npm.taobao.org/eslint/download/eslint-6.8.0.tgz", - "integrity": "sha1-YiYtZylzn5J1cjgkMC+yJ8jJP/s=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-5.1.0.tgz?cache=0&sync_timestamp=1591269986906&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-5.1.0.tgz", - "integrity": "sha1-0Plx3+WcaeDK2mhLI9Sdv4JgDOU=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npm.taobao.org/globals/download/globals-12.4.0.tgz", - "integrity": "sha1-oYgTV2pBsAokqX5/gVkYwuGZJfg=", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.2.1.tgz?cache=0&sync_timestamp=1589682760620&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-3.2.1.tgz", - "integrity": "sha1-Yz/2GFBueTr1rJG/SLcmd+FcvmY=", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npm.taobao.org/type-fest/download/type-fest-0.8.1.tgz", - "integrity": "sha1-CeJJ696FHTseSNJ8EFREZn8XuD0=", - "dev": true - } - } - }, - "eslint-loader": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/eslint-loader/download/eslint-loader-2.2.1.tgz", - "integrity": "sha1-KLnBLaVAV68IReKmEScBova/gzc=", - "dev": true, - "requires": { - "loader-fs-cache": "^1.0.0", - "loader-utils": "^1.0.2", - "object-assign": "^4.0.1", - "object-hash": "^1.1.4", - "rimraf": "^2.6.1" - } - }, - "eslint-plugin-vue": { - "version": "7.0.0-beta.2", - "resolved": "https://registry.npm.taobao.org/eslint-plugin-vue/download/eslint-plugin-vue-7.0.0-beta.2.tgz?cache=0&sync_timestamp=1597198168566&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-plugin-vue%2Fdownload%2Feslint-plugin-vue-7.0.0-beta.2.tgz", - "integrity": "sha1-SCiSPsJBkwYPgFZ7+MFbGOE5aLM=", - "dev": true, - "requires": { - "eslint-utils": "^2.1.0", - "natural-compare": "^1.4.0", - "semver": "^7.3.2", - "vue-eslint-parser": "^7.1.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/eslint-utils/download/eslint-utils-2.1.0.tgz", - "integrity": "sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc=", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.2.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.2.tgz", - "integrity": "sha1-YElisFK4HtB4aq6EOJ/7pw/9OTg=", - "dev": true - } - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.3.tgz?cache=0&sync_timestamp=1591269986906&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-4.0.3.tgz", - "integrity": "sha1-ygODMxD2iJoyZHgaqC5j65z+eEg=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npm.taobao.org/eslint-utils/download/eslint-utils-1.4.3.tgz", - "integrity": "sha1-dP7HxU0Hdrb2fgJRBAtYBlZOmB8=", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz?cache=0&sync_timestamp=1597435068105&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.3.0.tgz", - "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=", - "dev": true - }, - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npm.taobao.org/espree/download/espree-6.2.1.tgz?cache=0&sync_timestamp=1595034145062&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fespree%2Fdownload%2Fespree-6.2.1.tgz", - "integrity": "sha1-d/xy4f10SiBSwg84pbV1gy6Cc0o=", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-7.4.0.tgz?cache=0&sync_timestamp=1597235774928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-7.4.0.tgz", - "integrity": "sha1-4a1IbmxUUBY0xsOXxcEh2qODYHw=", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz?cache=0&sync_timestamp=1589682833047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fesprima%2Fdownload%2Fesprima-4.0.1.tgz", - "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", - "dev": true - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/esquery/download/esquery-1.3.1.tgz", - "integrity": "sha1-t4tYKKqOIU4p+3TE1bdS4cAz2lc=", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-5.2.0.tgz?cache=0&sync_timestamp=1596642998635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-5.2.0.tgz", - "integrity": "sha1-MH30JUfmzHMk088DwVXVzbjFOIA=", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/esrecurse/download/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-4.3.0.tgz?cache=0&sync_timestamp=1596642998635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-4.3.0.tgz", - "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", - "dev": true - }, - "estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/estree-walker/download/estree-walker-2.0.1.tgz", - "integrity": "sha1-+OAw+yHO+hg7RLetUWt0dDTno+A=" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz?cache=0&sync_timestamp=1589682816934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fesutils%2Fdownload%2Fesutils-2.0.3.tgz", - "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "event-pubsub": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/event-pubsub/download/event-pubsub-4.3.0.tgz", - "integrity": "sha1-9o2Ba8KfHsAsU53FjI3UDOcss24=", - "dev": true - }, - "eventemitter3": { - "version": "4.0.4", - "resolved": "https://registry.npm.taobao.org/eventemitter3/download/eventemitter3-4.0.4.tgz", - "integrity": "sha1-tUY6zmNaCD0Bi9x8kXtMXxCoU4Q=", - "dev": true - }, - "events": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/events/download/events-3.2.0.tgz?cache=0&sync_timestamp=1595422577337&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fevents%2Fdownload%2Fevents-3.2.0.tgz", - "integrity": "sha1-k7h8GPjvzUICpGGuxN/AVWtjk3k=", - "dev": true - }, - "eventsource": { - "version": "1.0.7", - "resolved": "https://registry.npm.taobao.org/eventsource/download/eventsource-1.0.7.tgz", - "integrity": "sha1-j7xyyT/NNAiAkLwKTmT0tc7m2NA=", - "dev": true, - "requires": { - "original": "^1.0.0" - } - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/evp_bytestokey/download/evp_bytestokey-1.0.3.tgz", - "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/execa/download/execa-1.0.0.tgz", - "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npm.taobao.org/express/download/express-4.17.1.tgz?cache=0&sync_timestamp=1589682766604&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexpress%2Fdownload%2Fexpress-4.17.1.tgz", - "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", - "dev": true, - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz", - "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz?cache=0&sync_timestamp=1589682707348&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fextend%2Fdownload%2Fextend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/external-editor/download/external-editor-3.1.0.tgz", - "integrity": "sha1-ywP3QL764D6k0oPK7SdBqD8zVJU=", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/extglob/download/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", - "dev": true - }, - "fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npm.taobao.org/fast-glob/download/fast-glob-2.2.7.tgz?cache=0&sync_timestamp=1592291968616&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-glob%2Fdownload%2Ffast-glob-2.2.7.tgz", - "integrity": "sha1-aVOFfDr6R1//ku5gFdUtpwpM050=", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.2.tgz", - "integrity": "sha1-tO7oFIq7Adzx0aw0Nn1Z4S+mHW4=", - "dev": true - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/figures/download/figures-3.2.0.tgz", - "integrity": "sha1-YlwYvSk8YE3EqN2y/r8MiDQXRq8=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/file-entry-cache/download/file-entry-cache-5.0.1.tgz", - "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "file-loader": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/file-loader/download/file-loader-4.3.0.tgz", - "integrity": "sha1-eA8ED3KbPRgBnyBgX3I+hEuKWK8=", - "dev": true, - "requires": { - "loader-utils": "^1.2.3", - "schema-utils": "^2.5.0" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz", - "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=", - "dev": true, - "optional": true - }, - "filesize": { - "version": "3.6.1", - "resolved": "https://registry.npm.taobao.org/filesize/download/filesize-3.6.1.tgz", - "integrity": "sha1-CQuz7gG2+AGoqL6Z0xcQs0Irsxc=", - "dev": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.2.tgz", - "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-2.1.0.tgz", - "integrity": "sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-3.0.0.tgz?cache=0&sync_timestamp=1597169842138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-3.0.0.tgz", - "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/flat-cache/download/flat-cache-2.0.1.tgz", - "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz?cache=0&sync_timestamp=1589682814592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.6.3.tgz", - "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/flatted/download/flatted-2.0.2.tgz", - "integrity": "sha1-RXWyHivO50NKqb5mL0t7X5wrUTg=", - "dev": true - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/flush-write-stream/download/flush-write-stream-1.1.1.tgz", - "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.0.tgz?cache=0&sync_timestamp=1597057976909&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.13.0.tgz", - "integrity": "sha1-tC6Nk6Kn7qXtiGM2dtZZe8jjhNs=", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz", - "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz?cache=0&sync_timestamp=1589682752100&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffresh%2Fdownload%2Ffresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/from2/download/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/fs-extra/download/fs-extra-7.0.1.tgz?cache=0&sync_timestamp=1591229972229&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffs-extra%2Fdownload%2Ffs-extra-7.0.1.tgz", - "integrity": "sha1-TxicRKoSO4lfcigE9V6iPq3DSOk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/fs-minipass/download/fs-minipass-2.1.0.tgz", - "integrity": "sha1-f1A2/b8SxjwWkZDL5BmchSJx+fs=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npm.taobao.org/fs-write-stream-atomic/download/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.1.3.tgz", - "integrity": "sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4=", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "generic-names": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/generic-names/download/generic-names-2.0.1.tgz", - "integrity": "sha1-+KN46tLMqno08DF7BVVIMq5BuHI=", - "dev": true, - "requires": { - "loader-utils": "^1.1.0" - } - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.1.tgz", - "integrity": "sha1-WPQ2H/mH5f9uHnohCCeqNx6qwmk=", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz", - "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-4.1.0.tgz?cache=0&sync_timestamp=1597056502934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-stream%2Fdownload%2Fget-stream-4.1.0.tgz", - "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz?cache=0&sync_timestamp=1589682745510&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgetpass%2Fdownload%2Fgetpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1589682812051&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz", - "integrity": "sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz", - "integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/glob-to-regexp/download/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npm.taobao.org/globals/download/globals-11.12.0.tgz", - "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", - "dev": true - }, - "globby": { - "version": "9.2.0", - "resolved": "https://registry.npm.taobao.org/globby/download/globby-9.2.0.tgz?cache=0&sync_timestamp=1591083812416&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-9.2.0.tgz", - "integrity": "sha1-/QKacGxwPSm90XD0tts6P3p8tj0=", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz?cache=0&sync_timestamp=1589682809142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgraceful-fs%2Fdownload%2Fgraceful-fs-4.2.4.tgz", - "integrity": "sha1-Ila94U02MpWMRl68ltxGfKB6Kfs=", - "dev": true - }, - "gzip-size": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/gzip-size/download/gzip-size-5.1.1.tgz", - "integrity": "sha1-y5vuaS+HwGErIyhAqHOQTkwTUnQ=", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "pify": "^4.0.1" - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/handle-thing/download/handle-thing-2.0.1.tgz", - "integrity": "sha1-hX95zjWVgMNA1DCBzGSJcNC7I04=", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npm.taobao.org/har-validator/download/har-validator-5.1.5.tgz?cache=0&sync_timestamp=1596082584903&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhar-validator%2Fdownload%2Fhar-validator-5.1.5.tgz", - "integrity": "sha1-HwgDufjLIMD6E4It8ezds2veHv0=", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/has-ansi/download/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.1.tgz", - "integrity": "sha1-n1IUdYpEGWxAbZvXbOv4HsLdMeg=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/hash-base/download/hash-base-3.1.0.tgz", - "integrity": "sha1-VcOB2eBuHSmXqIO0o/3f5/DTrzM=", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz?cache=0&sync_timestamp=1589682741447&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz?cache=0&sync_timestamp=1589682795646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.2.1.tgz", - "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", - "dev": true - } - } - }, - "hash-sum": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-2.0.0.tgz", - "integrity": "sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo=", - "dev": true - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npm.taobao.org/hash.js/download/hash.js-1.1.7.tgz", - "integrity": "sha1-C6vKU46NTuSg+JiNaIZlN6ADz0I=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/he/download/he-1.2.0.tgz?cache=0&sync_timestamp=1589682765156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhe%2Fdownload%2Fhe-1.2.0.tgz", - "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=", - "dev": true - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/hex-color-regex/download/hex-color-regex-1.1.0.tgz", - "integrity": "sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=", - "dev": true - }, - "highlight.js": { - "version": "9.18.3", - "resolved": "https://registry.npm.taobao.org/highlight.js/download/highlight.js-9.18.3.tgz", - "integrity": "sha1-oaCiAo1eMUniOA+Khl7oUWcD1jQ=", - "dev": true - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/hmac-drbg/download/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/hoopy/download/hoopy-0.1.4.tgz", - "integrity": "sha1-YJIH1mEQADOpqUAq096mdzgcGx0=", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.8.tgz?cache=0&sync_timestamp=1594427993800&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhosted-git-info%2Fdownload%2Fhosted-git-info-2.8.8.tgz", - "integrity": "sha1-dTm9S8Hg4KiVgVouAmJCCxKFhIg=", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npm.taobao.org/hpack.js/download/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/hsl-regex/download/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/hsla-regex/download/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, - "html-comment-regex": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/html-comment-regex/download/html-comment-regex-1.1.2.tgz", - "integrity": "sha1-l9RoiutcgYhqNk+qDK0d2hTUM6c=", - "dev": true - }, - "html-entities": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/html-entities/download/html-entities-1.3.1.tgz", - "integrity": "sha1-+5oaS1sUxdq6gtPjTGrk/nAaDkQ=", - "dev": true - }, - "html-minifier": { - "version": "3.5.21", - "resolved": "https://registry.npm.taobao.org/html-minifier/download/html-minifier-3.5.21.tgz", - "integrity": "sha1-0AQOBUcw41TbAIRjWTGUAVIS0gw=", - "dev": true, - "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.17.1.tgz", - "integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78=", - "dev": true - } - } - }, - "html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-3.1.0.tgz", - "integrity": "sha1-e15vfmZen7QfMAB+2eDUHpf7IUA=", - "dev": true - }, - "html-webpack-plugin": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz", - "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", - "dev": true, - "requires": { - "html-minifier": "^3.2.3", - "loader-utils": "^0.2.16", - "lodash": "^4.17.3", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", - "toposort": "^1.0.0", - "util.promisify": "1.0.0" - }, - "dependencies": { - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/big.js/download/big.js-3.2.0.tgz", - "integrity": "sha1-pfwpi4G54Nyi5FiCR4S2XFK6WI4=", - "dev": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npm.taobao.org/json5/download/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.0.tgz?cache=0&sync_timestamp=1589682767473&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil.promisify%2Fdownload%2Futil.promisify-1.0.0.tgz", - "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - } - } - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npm.taobao.org/htmlparser2/download/htmlparser2-3.10.1.tgz", - "integrity": "sha1-vWedw/WYl7ajS7EHSchVu1OpOS8=", - "dev": true, - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/entities/download/entities-1.1.2.tgz", - "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=", - "dev": true - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz?cache=0&sync_timestamp=1589682741447&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npm.taobao.org/http-deceiver/download/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.2.tgz?cache=0&sync_timestamp=1593407858306&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.2.tgz", - "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npm.taobao.org/http-proxy/download/http-proxy-1.18.1.tgz", - "integrity": "sha1-QBVB8FNIhLv5UmAzTnL4juOXZUk=", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npm.taobao.org/http-proxy-middleware/download/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha1-GDx9xKoUeRUDBkmMIQza+WCApDo=", - "dev": true, - "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz?cache=0&sync_timestamp=1589682811784&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-signature%2Fdownload%2Fhttp-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/https-browserify/download/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/human-signals/download/human-signals-1.1.1.tgz", - "integrity": "sha1-xbHNFPUK6uCatsWf5jujOV/k36M=", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184264130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/icss-replace-symbols/download/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true - }, - "icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/icss-utils/download/icss-utils-4.1.1.tgz", - "integrity": "sha1-IRcLU3ie4nRHwvR91oMIFAP5pGc=", - "dev": true, - "requires": { - "postcss": "^7.0.14" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npm.taobao.org/ieee754/download/ieee754-1.1.13.tgz", - "integrity": "sha1-7BaFWOlaoYH9h9N/VcMrvLZwi4Q=", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", - "dev": true - }, - "import-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/import-cwd/download/import-cwd-2.1.0.tgz", - "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "dev": true, - "requires": { - "import-from": "^2.1.0" - } - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz?cache=0&sync_timestamp=1589682760620&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-from": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/import-from/download/import-from-2.1.0.tgz", - "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/import-local/download/import-local-2.0.0.tgz", - "integrity": "sha1-VQcL44pZk88Y72236WH1vuXFoJ0=", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/indent-string/download/indent-string-4.0.0.tgz", - "integrity": "sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE=", - "dev": true - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/infer-owner/download/infer-owner-1.0.4.tgz", - "integrity": "sha1-xM78qo5RBRwqQLos6KPScpWvlGc=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", - "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", - "dev": true - }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npm.taobao.org/inquirer/download/inquirer-7.3.3.tgz", - "integrity": "sha1-BNF2sq8Er8FXqD/XwQDpjuCq0AM=", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz", - "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-3.1.0.tgz", - "integrity": "sha1-JkMFp65JDR0Dvwybp8kl0XU68wc=", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-2.1.0.tgz?cache=0&sync_timestamp=1596095644798&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmimic-fn%2Fdownload%2Fmimic-fn-2.1.0.tgz", - "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", - "dev": true - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-5.1.2.tgz?cache=0&sync_timestamp=1597005345612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fonetime%2Fdownload%2Fonetime-5.1.2.tgz", - "integrity": "sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-3.1.0.tgz", - "integrity": "sha1-OfZ8VLOnpYzqUjbZXPADQjljH34=", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/internal-ip/download/internal-ip-4.3.0.tgz?cache=0&sync_timestamp=1596563037835&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finternal-ip%2Fdownload%2Finternal-ip-4.3.0.tgz", - "integrity": "sha1-hFRSuq2dLKO2nGNaE3rLmg2tCQc=", - "dev": true, - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - }, - "dependencies": { - "default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/default-gateway/download/default-gateway-4.2.0.tgz", - "integrity": "sha1-FnEEx1AMIRX23WmwpTa7jtcgVSs=", - "dev": true, - "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - } - } - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/interpret/download/interpret-1.4.0.tgz", - "integrity": "sha1-Zlq4vE2iendKQFhOgS4+D6RbGh4=", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npm.taobao.org/invariant/download/invariant-2.2.4.tgz", - "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/ip-regex/download/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.9.1.tgz", - "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=", - "dev": true - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-absolute-url/download/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/is-arguments/download/is-arguments-1.0.4.tgz", - "integrity": "sha1-P6+WbHy6D/Q3+zH2JQCC/PBEjPM=", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz", - "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/is-callable/download/is-callable-1.2.0.tgz", - "integrity": "sha1-gzNlYLVKOONeOi33r9BFTWkUaLs=", - "dev": true - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/is-ci/download/is-ci-1.2.1.tgz?cache=0&sync_timestamp=1589682764432&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-ci%2Fdownload%2Fis-ci-1.2.1.tgz", - "integrity": "sha1-43ecjuF/zPQoSI9uKBGH8uYyhBw=", - "dev": true, - "requires": { - "ci-info": "^1.5.0" - } - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-color-stop/download/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.2.tgz", - "integrity": "sha1-vac28s2P0G0yhE53Q7+nSUw7/X4=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npm.taobao.org/is-directory/download/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/is-docker/download/is-docker-2.1.1.tgz", - "integrity": "sha1-QSWojkTkUNOE4JBH7eca3C0UQVY=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz", - "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-obj/download/is-obj-2.0.0.tgz", - "integrity": "sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI=", - "dev": true - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/is-path-cwd/download/is-path-cwd-2.2.0.tgz", - "integrity": "sha1-Z9Q7gmZKe1GR/ZEZEn6zAASKn9s=", - "dev": true - }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-path-in-cwd/download/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha1-v+Lcomxp85cmWkAJljYCk1oFOss=", - "dev": true, - "requires": { - "is-path-inside": "^2.1.0" - } - }, - "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-path-inside/download/is-path-inside-2.1.0.tgz", - "integrity": "sha1-fJgQWH1lmkDSe8201WFuqwWUlLI=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.2" - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-plain-obj/download/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/is-plain-object/download/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/is-regex/download/is-regex-1.1.1.tgz?cache=0&sync_timestamp=1596555640677&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-regex%2Fdownload%2Fis-regex-1.1.1.tgz", - "integrity": "sha1-xvmKrMVG9s7FRooHt7FTq1ZKV7k=", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-resolvable/download/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-svg": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-svg/download/is-svg-3.0.0.tgz", - "integrity": "sha1-kyHb0pwhLlypnE+peUxxS8r6L3U=", - "dev": true, - "requires": { - "html-comment-regex": "^1.1.0" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/is-symbol/download/is-symbol-1.0.3.tgz", - "integrity": "sha1-OOEBS55jKb4N6dJKQU/XRB7GGTc=", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "javascript-stringify": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/javascript-stringify/download/javascript-stringify-2.0.1.tgz", - "integrity": "sha1-bvNYA1MQ411mfGde1j0+t8GqGeU=", - "dev": true - }, - "jest-worker": { - "version": "25.5.0", - "resolved": "https://registry.npm.taobao.org/jest-worker/download/jest-worker-25.5.0.tgz?cache=0&sync_timestamp=1597057499649&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-worker%2Fdownload%2Fjest-worker-25.5.0.tgz", - "integrity": "sha1-JhHQcbec6g9D7lej0RhZOsFUfbE=", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-message": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.5.tgz", - "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", - "dev": true - }, - "js-queue": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/js-queue/download/js-queue-2.0.0.tgz", - "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", - "dev": true, - "requires": { - "easy-stack": "^1.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz", - "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", - "dev": true - }, - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npm.taobao.org/js-yaml/download/js-yaml-3.14.0.tgz", - "integrity": "sha1-p6NBcPJqIbsWJCTYray0ETpp5II=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz?cache=0&sync_timestamp=1589682745609&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjsbn%2Fdownload%2Fjsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz", - "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/json-parse-better-errors/download/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz?cache=0&sync_timestamp=1589682771374&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-stringify-safe%2Fdownload%2Fjson-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npm.taobao.org/json3/download/json3-3.3.3.tgz", - "integrity": "sha1-f8EON1/FrkLEcFpcwKpvYr4wW4E=", - "dev": true - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/json5/download/json5-2.1.3.tgz", - "integrity": "sha1-ybD3+pIzv+WAf+ZvzzpWF+1ZfUM=", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/killable/download/killable-1.0.1.tgz", - "integrity": "sha1-TIzkQRh6Bhx0dPuHygjipjgZSJI=", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - }, - "launch-editor": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/launch-editor/download/launch-editor-2.2.1.tgz", - "integrity": "sha1-hxtaPuOdZoD8wm03kwtu7aidsMo=", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "shell-quote": "^1.6.1" - } - }, - "launch-editor-middleware": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/launch-editor-middleware/download/launch-editor-middleware-2.2.1.tgz", - "integrity": "sha1-4UsH5scVSwpLhqD9NFeE5FgEwVc=", - "dev": true, - "requires": { - "launch-editor": "^2.2.1" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/leven/download/leven-3.1.0.tgz", - "integrity": "sha1-d4kd6DQGTMy6gq54QrtrFKE+1/I=", - "dev": true - }, - "levenary": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/levenary/download/levenary-1.1.1.tgz", - "integrity": "sha1-hCqe6Y0gdap/ru2+MmeekgX0b3c=", - "dev": true, - "requires": { - "leven": "^3.1.0" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npm.taobao.org/lines-and-columns/download/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "loader-fs-cache": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/loader-fs-cache/download/loader-fs-cache-1.0.3.tgz", - "integrity": "sha1-8IZXZG1gcHi+LwoDL4vWndbyd9k=", - "dev": true, - "requires": { - "find-cache-dir": "^0.1.1", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-0.1.1.tgz", - "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-1.1.2.tgz?cache=0&sync_timestamp=1597169842138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, - "requires": { - "find-up": "^1.0.0" - } - } - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/loader-runner/download/loader-runner-2.4.0.tgz?cache=0&sync_timestamp=1593786221739&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Floader-runner%2Fdownload%2Floader-runner-2.4.0.tgz", - "integrity": "sha1-7UcGa/5TTX6ExMe5mYwqdWB9k1c=", - "dev": true - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-1.4.0.tgz", - "integrity": "sha1-xXm140yzSxp07cbB+za/o3HVphM=", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz", - "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", - "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597335994883&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz", - "integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI=" - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true - }, - "lodash.defaultsdeep": { - "version": "4.6.1", - "resolved": "https://registry.npm.taobao.org/lodash.defaultsdeep/download/lodash.defaultsdeep-4.6.1.tgz", - "integrity": "sha1-US6b1yHSctlOPTpjZT+hdRZ0HKY=", - "dev": true - }, - "lodash.kebabcase": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/lodash.kebabcase/download/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", - "dev": true - }, - "lodash.mapvalues": { - "version": "4.6.0", - "resolved": "https://registry.npm.taobao.org/lodash.mapvalues/download/lodash.mapvalues-4.6.0.tgz", - "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz?cache=0&sync_timestamp=1589682725270&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.memoize%2Fdownload%2Flodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.transform": { - "version": "4.6.0", - "resolved": "https://registry.npm.taobao.org/lodash.transform/download/lodash.transform-4.6.0.tgz", - "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npm.taobao.org/lodash.uniq/download/lodash.uniq-4.5.0.tgz?cache=0&sync_timestamp=1589682817275&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.uniq%2Fdownload%2Flodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/log-symbols/download/log-symbols-2.2.0.tgz", - "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "loglevel": { - "version": "1.6.8", - "resolved": "https://registry.npm.taobao.org/loglevel/download/loglevel-1.6.8.tgz", - "integrity": "sha1-iiX7ddCSIw7NRFcnDYC1TigBEXE=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz", - "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "dev": true - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-5.1.1.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-5.1.1.tgz", - "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npm.taobao.org/magic-string/download/magic-string-0.25.7.tgz", - "integrity": "sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE=", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-2.1.0.tgz", - "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npm.taobao.org/map-cache/download/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/map-visit/download/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz", - "integrity": "sha1-tdB7jjIW4+J81yjXL3DR5qNCAF8=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/mdn-data/download/mdn-data-2.0.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmdn-data%2Fdownload%2Fmdn-data-2.0.4.tgz", - "integrity": "sha1-aZs8OKxvHXKAkaZGULZdOIUC/Vs=", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npm.taobao.org/memory-fs/download/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/merge-source-map/download/merge-source-map-1.1.0.tgz", - "integrity": "sha1-L93n5gIJOfcJBqaPLXrmheTIxkY=", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/merge-stream/download/merge-stream-2.0.0.tgz?cache=0&sync_timestamp=1589682763068&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmerge-stream%2Fdownload%2Fmerge-stream-2.0.0.tgz", - "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/merge2/download/merge2-1.4.1.tgz", - "integrity": "sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4=", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/miller-rabin/download/miller-rabin-4.0.1.tgz", - "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "mime": { - "version": "2.4.6", - "resolved": "https://registry.npm.taobao.org/mime/download/mime-2.4.6.tgz?cache=0&sync_timestamp=1590635592890&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime%2Fdownload%2Fmime-2.4.6.tgz", - "integrity": "sha1-5bQHyQ20QvK+tbFiNz0Htpr/pNE=", - "dev": true - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npm.taobao.org/mime-db/download/mime-db-1.44.0.tgz", - "integrity": "sha1-+hHF6wrKEzS0Izy01S8QxaYnL5I=", - "dev": true - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.27.tgz?cache=0&sync_timestamp=1589682770020&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-types%2Fdownload%2Fmime-types-2.1.27.tgz", - "integrity": "sha1-R5SfmOJ56lMRn1ci4PNOUpvsAJ8=", - "dev": true, - "requires": { - "mime-db": "1.44.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-1.2.0.tgz?cache=0&sync_timestamp=1596095644798&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmimic-fn%2Fdownload%2Fmimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", - "dev": true - }, - "mini-css-extract-plugin": { - "version": "0.9.0", - "resolved": "https://registry.npm.taobao.org/mini-css-extract-plugin/download/mini-css-extract-plugin-0.9.0.tgz?cache=0&sync_timestamp=1597072282658&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmini-css-extract-plugin%2Fdownload%2Fmini-css-extract-plugin-0.9.0.tgz", - "integrity": "sha1-R/LPB6oWWrNXM7H8l9TEbAVkM54=", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "normalize-url": "1.9.1", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" - }, - "dependencies": { - "normalize-url": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/normalize-url/download/normalize-url-1.9.1.tgz?cache=0&sync_timestamp=1596373165623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-url%2Fdownload%2Fnormalize-url-1.9.1.tgz", - "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "prepend-http": "^1.0.0", - "query-string": "^4.1.0", - "sort-keys": "^1.0.0" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/minimalistic-assert/download/minimalistic-assert-1.0.1.tgz", - "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/minimalistic-crypto-utils/download/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz?cache=0&sync_timestamp=1589682820731&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminimist%2Fdownload%2Fminimist-1.2.5.tgz", - "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=", - "dev": true - }, - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npm.taobao.org/minipass/download/minipass-3.1.3.tgz?cache=0&sync_timestamp=1589683712023&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminipass%2Fdownload%2Fminipass-3.1.3.tgz", - "integrity": "sha1-fUL/HzljVILhX5zbUxhN7r1YFf0=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", - "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", - "dev": true - } - } - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/minipass-collect/download/minipass-collect-1.0.2.tgz", - "integrity": "sha1-IrgTv3Rdxu26JXa5QAIq1u3Ixhc=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/minipass-flush/download/minipass-flush-1.0.5.tgz", - "integrity": "sha1-gucTXX6JpQ/+ZGEKeHlTxMTLs3M=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npm.taobao.org/minipass-pipeline/download/minipass-pipeline-1.2.4.tgz?cache=0&sync_timestamp=1595998621838&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminipass-pipeline%2Fdownload%2Fminipass-pipeline-1.2.4.tgz", - "integrity": "sha1-aEcveXEcCEZXwGfFxq2Tzd6oIUw=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/mississippi/download/mississippi-3.0.0.tgz", - "integrity": "sha1-6goykfl+C16HdrNj1fChLZTGcCI=", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/mixin-deep/download/mixin-deep-1.3.2.tgz", - "integrity": "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY=", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz?cache=0&sync_timestamp=1589682820707&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-0.5.5.tgz", - "integrity": "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz", - "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", - "dev": true - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npm.taobao.org/multicast-dns/download/multicast-dns-6.2.3.tgz", - "integrity": "sha1-oOx72QVcQoL3kMPIL04o2zsxsik=", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/multicast-dns-service-types/download/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.8.tgz", - "integrity": "sha1-FjDEKyJR/4HiooPelqVJfqkuXg0=", - "dev": true - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz", - "integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=", - "dev": true, - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npm.taobao.org/nan/download/nan-2.14.1.tgz?cache=0&sync_timestamp=1589682780413&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnan%2Fdownload%2Fnan-2.14.1.tgz", - "integrity": "sha1-174036MQW5FJTDFHCJMV7/iHSwE=", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz", - "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz?cache=0&sync_timestamp=1589682752355&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnegotiator%2Fdownload%2Fnegotiator-0.6.2.tgz", - "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz?cache=0&sync_timestamp=1594317434347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fneo-async%2Fdownload%2Fneo-async-2.6.2.tgz", - "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/nice-try/download/nice-try-1.0.5.tgz", - "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", - "dev": true - }, - "no-case": { - "version": "2.3.2", - "resolved": "https://registry.npm.taobao.org/no-case/download/no-case-2.3.2.tgz", - "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", - "dev": true, - "requires": { - "lower-case": "^1.1.1" - } - }, - "node-forge": { - "version": "0.9.0", - "resolved": "https://registry.npm.taobao.org/node-forge/download/node-forge-0.9.0.tgz", - "integrity": "sha1-1iQFDtu0SHStyhK7mlLsY8t4JXk=", - "dev": true - }, - "node-ipc": { - "version": "9.1.1", - "resolved": "https://registry.npm.taobao.org/node-ipc/download/node-ipc-9.1.1.tgz", - "integrity": "sha1-TiRe1pOOZRAOWV68XcNLFujdXWk=", - "dev": true, - "requires": { - "event-pubsub": "4.3.0", - "js-message": "1.0.5", - "js-queue": "2.0.0" - } - }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/node-libs-browser/download/node-libs-browser-2.2.1.tgz", - "integrity": "sha1-tk9RPRgzhiX5A0bSew0jXmMfZCU=", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz?cache=0&sync_timestamp=1589682803838&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpunycode%2Fdownload%2Fpunycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "node-releases": { - "version": "1.1.60", - "resolved": "https://registry.npm.taobao.org/node-releases/download/node-releases-1.1.60.tgz?cache=0&sync_timestamp=1595485377499&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-releases%2Fdownload%2Fnode-releases-1.1.60.tgz", - "integrity": "sha1-aUi9/OgobwtdDlqI6DhOlU3+cIQ=", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-2.5.0.tgz", - "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", - "dev": true - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/normalize-range/download/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npm.taobao.org/normalize-url/download/normalize-url-3.3.0.tgz?cache=0&sync_timestamp=1596373165623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-url%2Fdownload%2Fnormalize-url-3.3.0.tgz", - "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/nth-check/download/nth-check-1.0.2.tgz", - "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, - "null-loader": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/null-loader/download/null-loader-3.0.0.tgz", - "integrity": "sha1-PitsZjxb2oxzpUNX2PoHCNxhskU=", - "dev": true, - "requires": { - "loader-utils": "^1.2.3", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npm.taobao.org/num2fraction/download/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz?cache=0&sync_timestamp=1589682811909&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Foauth-sign%2Fdownload%2Foauth-sign-0.9.0.tgz", - "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/object-hash/download/object-hash-1.3.1.tgz", - "integrity": "sha1-/eRSCYqVHLFF8Dm7fUVUSd3BJt8=", - "dev": true - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.8.0.tgz?cache=0&sync_timestamp=1592545231350&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-inspect%2Fdownload%2Fobject-inspect-1.8.0.tgz", - "integrity": "sha1-34B+Xs9TpgnMa/6T6sPMe+WzqdA=", - "dev": true - }, - "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/object-is/download/object-is-1.1.2.tgz", - "integrity": "sha1-xdLof/nhGfeLegiEQVGeLuwVc7Y=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/object-keys/download/object-keys-1.1.1.tgz", - "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/object.assign/download/object.assign-4.1.0.tgz", - "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/object.getownpropertydescriptors/download/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha1-Npvx+VktiridcS3O1cuBx8U1Jkk=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/object.values/download/object.values-1.1.1.tgz", - "integrity": "sha1-aKmezeNWt+kpWjxeDOMdyMlT3l4=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/obuf/download/obuf-1.1.2.tgz", - "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=", - "dev": true - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/on-headers/download/on-headers-1.0.2.tgz", - "integrity": "sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-2.0.1.tgz?cache=0&sync_timestamp=1597005345612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fonetime%2Fdownload%2Fonetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "open": { - "version": "6.4.0", - "resolved": "https://registry.npm.taobao.org/open/download/open-6.4.0.tgz?cache=0&sync_timestamp=1595208443014&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fopen%2Fdownload%2Fopen-6.4.0.tgz", - "integrity": "sha1-XBPpbQ3IlGhhZPGJZez+iJ7PyKk=", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "opener": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/opener/download/opener-1.5.1.tgz?cache=0&sync_timestamp=1589682813674&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fopener%2Fdownload%2Fopener-1.5.1.tgz", - "integrity": "sha1-bS8Od/GgrwAyrKcWwsH7uOfoq+0=", - "dev": true - }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npm.taobao.org/opn/download/opn-5.5.0.tgz", - "integrity": "sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w=", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npm.taobao.org/optionator/download/optionator-0.8.3.tgz", - "integrity": "sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "ora": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/ora/download/ora-3.4.0.tgz?cache=0&sync_timestamp=1596812605371&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fora%2Fdownload%2Fora-3.4.0.tgz", - "integrity": "sha1-vwdSSRBZo+8+1MhQl1Md6f280xg=", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-spinners": "^2.0.0", - "log-symbols": "^2.2.0", - "strip-ansi": "^5.2.0", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "original": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/original/download/original-1.0.2.tgz", - "integrity": "sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8=", - "dev": true, - "requires": { - "url-parse": "^1.4.3" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/os-browserify/download/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/os-tmpdir/download/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/p-limit/download/p-limit-2.3.0.tgz?cache=0&sync_timestamp=1594559734248&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-limit%2Fdownload%2Fp-limit-2.3.0.tgz", - "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-3.0.0.tgz", - "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/p-map/download/p-map-3.0.0.tgz", - "integrity": "sha1-1wTZr4orpoTiYA2aIVmD1BQal50=", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/p-retry/download/p-retry-3.0.1.tgz", - "integrity": "sha1-MWtMiJPiyNwc+okfQGxLQivr8yg=", - "dev": true, - "requires": { - "retry": "^0.12.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/p-try/download/p-try-2.2.0.tgz", - "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=", - "dev": true - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npm.taobao.org/pako/download/pako-1.0.11.tgz", - "integrity": "sha1-bJWZ00DVTf05RjgCUqNXBaa5kr8=", - "dev": true - }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/parallel-transform/download/parallel-transform-1.2.0.tgz", - "integrity": "sha1-kEnKN9bLIYLDsdLHIL6U0UpYFPw=", - "dev": true, - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "param-case": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/param-case/download/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/parent-module/download/parent-module-1.0.1.tgz", - "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", - "dev": true, - "requires": { - "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz", - "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", - "dev": true - } - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npm.taobao.org/parse-asn1/download/parse-asn1-5.1.6.tgz?cache=0&sync_timestamp=1597167309380&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparse-asn1%2Fdownload%2Fparse-asn1-5.1.6.tgz", - "integrity": "sha1-OFCAo+wTy2KmLTlAnLPoiETNrtQ=", - "dev": true, - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-json": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/parse-json/download/parse-json-5.0.1.tgz", - "integrity": "sha1-fP41wczWQbzjmBRn5sLs5hs7OHg=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" - } - }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/parse5/download/parse5-5.1.1.tgz?cache=0&sync_timestamp=1595849263958&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparse5%2Fdownload%2Fparse5-5.1.1.tgz", - "integrity": "sha1-9o5OW6GFKsLK3AD0VV//bCq7YXg=", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/parse5-htmlparser2-tree-adapter/download/parse5-htmlparser2-tree-adapter-5.1.1.tgz?cache=0&sync_timestamp=1596089818598&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparse5-htmlparser2-tree-adapter%2Fdownload%2Fparse5-htmlparser2-tree-adapter-5.1.1.tgz", - "integrity": "sha1-6MdD1OkhlNUpPs3isIvjHmdGHLw=", - "dev": true, - "requires": { - "parse5": "^5.1.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz", - "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npm.taobao.org/path-browserify/download/path-browserify-0.0.1.tgz", - "integrity": "sha1-5sTd1+06onxoogzE5Q4aTug7vEo=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/path-dirname/download/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/path-is-inside/download/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/path-parse/download/path-parse-1.0.6.tgz", - "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-3.0.0.tgz", - "integrity": "sha1-zvMdyOCho7sNEFwM2Xzzv0f0428=", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/pbkdf2/download/pbkdf2-3.1.1.tgz", - "integrity": "sha1-y4cksPramEWWhW0abrr9NYRlS5Q=", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npm.taobao.org/picomatch/download/picomatch-2.2.2.tgz", - "integrity": "sha1-IfMz6ba46v8CRo9RRupAbTRfTa0=", - "dev": true, - "optional": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/pinkie-promise/download/pinkie-promise-2.0.1.tgz?cache=0&sync_timestamp=1589682729560&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpinkie-promise%2Fdownload%2Fpinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-3.0.0.tgz", - "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "pnp-webpack-plugin": { - "version": "1.6.4", - "resolved": "https://registry.npm.taobao.org/pnp-webpack-plugin/download/pnp-webpack-plugin-1.6.4.tgz?cache=0&sync_timestamp=1589684269502&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpnp-webpack-plugin%2Fdownload%2Fpnp-webpack-plugin-1.6.4.tgz", - "integrity": "sha1-yXEaxNxIpoXauvyG+Lbdn434QUk=", - "dev": true, - "requires": { - "ts-pnp": "^1.1.6" - } - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npm.taobao.org/portfinder/download/portfinder-1.0.28.tgz?cache=0&sync_timestamp=1596018176291&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fportfinder%2Fdownload%2Fportfinder-1.0.28.tgz", - "integrity": "sha1-Z8RiKFK9U3TdHdkA93n1NGL6x3g=", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.6.tgz", - "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npm.taobao.org/postcss/download/postcss-7.0.32.tgz", - "integrity": "sha1-QxDW7jRwU9o0M9sr5JKIPWLOxZ0=", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-calc": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-calc/download/postcss-calc-7.0.3.tgz?cache=0&sync_timestamp=1596805654356&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-calc%2Fdownload%2Fpostcss-calc-7.0.3.tgz", - "integrity": "sha1-1lzKkqPFK/J603pfcy4Fh7dPFiM=", - "dev": true, - "requires": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-colormin/download/postcss-colormin-4.0.3.tgz?cache=0&sync_timestamp=1597682964214&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-colormin%2Fdownload%2Fpostcss-colormin-4.0.3.tgz", - "integrity": "sha1-rgYLzpPteUrHEmTwgTLVUJVr04E=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-convert-values/download/postcss-convert-values-4.0.1.tgz?cache=0&sync_timestamp=1597682964333&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-convert-values%2Fdownload%2Fpostcss-convert-values-4.0.1.tgz", - "integrity": "sha1-yjgT7U2g+BL51DcDWE5Enr4Ymn8=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-discard-comments/download/postcss-discard-comments-4.0.2.tgz?cache=0&sync_timestamp=1597682964431&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-discard-comments%2Fdownload%2Fpostcss-discard-comments-4.0.2.tgz", - "integrity": "sha1-H7q9LCRr/2qq15l7KwkY9NevQDM=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-discard-duplicates/download/postcss-discard-duplicates-4.0.2.tgz?cache=0&sync_timestamp=1597682964524&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-discard-duplicates%2Fdownload%2Fpostcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha1-P+EzzTyCKC5VD8myORdqkge3hOs=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-discard-empty/download/postcss-discard-empty-4.0.1.tgz?cache=0&sync_timestamp=1597682964629&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-discard-empty%2Fdownload%2Fpostcss-discard-empty-4.0.1.tgz", - "integrity": "sha1-yMlR6fc+2UKAGUWERKAq2Qu592U=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-discard-overridden/download/postcss-discard-overridden-4.0.1.tgz?cache=0&sync_timestamp=1597682964720&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-discard-overridden%2Fdownload%2Fpostcss-discard-overridden-4.0.1.tgz", - "integrity": "sha1-ZSrvipZybwKfXj4AFG7npOdV/1c=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-load-config": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/postcss-load-config/download/postcss-load-config-2.1.0.tgz", - "integrity": "sha1-yE1pK3u3tB3c7ZTuYuirMbQXsAM=", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" - } - }, - "postcss-loader": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/postcss-loader/download/postcss-loader-3.0.0.tgz", - "integrity": "sha1-a5eUPkfHLYRfqeA/Jzdz1OjdbC0=", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npm.taobao.org/postcss-merge-longhand/download/postcss-merge-longhand-4.0.11.tgz?cache=0&sync_timestamp=1597684735557&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-merge-longhand%2Fdownload%2Fpostcss-merge-longhand-4.0.11.tgz", - "integrity": "sha1-YvSaE+Sg7gTnuY9CuxYGLKJUniQ=", - "dev": true, - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-merge-rules/download/postcss-merge-rules-4.0.3.tgz?cache=0&sync_timestamp=1597684597276&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-merge-rules%2Fdownload%2Fpostcss-merge-rules-4.0.3.tgz", - "integrity": "sha1-NivqT/Wh+Y5AdacTxsslrv75plA=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-font-values/download/postcss-minify-font-values-4.0.2.tgz?cache=0&sync_timestamp=1597684597341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-minify-font-values%2Fdownload%2Fpostcss-minify-font-values-4.0.2.tgz", - "integrity": "sha1-zUw0TM5HQ0P6xdgiBqssvLiv1aY=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-gradients/download/postcss-minify-gradients-4.0.2.tgz?cache=0&sync_timestamp=1597684736463&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-minify-gradients%2Fdownload%2Fpostcss-minify-gradients-4.0.2.tgz", - "integrity": "sha1-k7KcL/UJnFNe7NpWxKpuZlpmNHE=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-params/download/postcss-minify-params-4.0.2.tgz?cache=0&sync_timestamp=1597684736706&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-minify-params%2Fdownload%2Fpostcss-minify-params-4.0.2.tgz", - "integrity": "sha1-a5zvAwwR41Jh+V9hjJADbWgNuHQ=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-selectors/download/postcss-minify-selectors-4.0.2.tgz?cache=0&sync_timestamp=1597684737076&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-minify-selectors%2Fdownload%2Fpostcss-minify-selectors-4.0.2.tgz", - "integrity": "sha1-4uXrQL/uUA0M2SQ1APX46kJi+9g=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-modules": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/postcss-modules/download/postcss-modules-3.2.0.tgz?cache=0&sync_timestamp=1593589775045&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules%2Fdownload%2Fpostcss-modules-3.2.0.tgz", - "integrity": "sha1-HKhw0ZfNCaeWQlPhLeKqyQbJQlY=", - "dev": true, - "requires": { - "generic-names": "^2.0.1", - "icss-replace-symbols": "^1.1.0", - "lodash.camelcase": "^4.3.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "string-hash": "^1.1.1" - } - }, - "postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/postcss-modules-extract-imports/download/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha1-gYcZoa4doyX5gyRGsBE27rSTzX4=", - "dev": true, - "requires": { - "postcss": "^7.0.5" - } - }, - "postcss-modules-local-by-default": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-modules-local-by-default/download/postcss-modules-local-by-default-3.0.3.tgz?cache=0&sync_timestamp=1595733620602&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-local-by-default%2Fdownload%2Fpostcss-modules-local-by-default-3.0.3.tgz", - "integrity": "sha1-uxTgzHgnnVBNvcv9fgyiiZP/u7A=", - "dev": true, - "requires": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.32", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha1-OFyuATzHdD9afXYC0Qc6iequYu4=", - "dev": true, - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - } - }, - "postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/postcss-modules-values/download/postcss-modules-values-3.0.0.tgz", - "integrity": "sha1-W1AA1uuuKbQlUwG0o6VFdEI+fxA=", - "dev": true, - "requires": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-charset/download/postcss-normalize-charset-4.0.1.tgz?cache=0&sync_timestamp=1597684737335&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-charset%2Fdownload%2Fpostcss-normalize-charset-4.0.1.tgz", - "integrity": "sha1-izWt067oOhNrBHHg1ZvlilAoXdQ=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-display-values/download/postcss-normalize-display-values-4.0.2.tgz?cache=0&sync_timestamp=1597683104006&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-display-values%2Fdownload%2Fpostcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha1-Db4EpM6QY9RmftK+R2u4MMglk1o=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-positions/download/postcss-normalize-positions-4.0.2.tgz?cache=0&sync_timestamp=1597683104141&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-positions%2Fdownload%2Fpostcss-normalize-positions-4.0.2.tgz", - "integrity": "sha1-BfdX+E8mBDc3g2ipH4ky1LECkX8=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-repeat-style/download/postcss-normalize-repeat-style-4.0.2.tgz?cache=0&sync_timestamp=1597683104230&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-repeat-style%2Fdownload%2Fpostcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha1-xOu8KJ85kaAo1EdRy90RkYsXkQw=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-string/download/postcss-normalize-string-4.0.2.tgz?cache=0&sync_timestamp=1597683104306&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-string%2Fdownload%2Fpostcss-normalize-string-4.0.2.tgz", - "integrity": "sha1-zUTECrB6DHo23F6Zqs4eyk7CaQw=", - "dev": true, - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-timing-functions/download/postcss-normalize-timing-functions-4.0.2.tgz?cache=0&sync_timestamp=1597683104399&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-timing-functions%2Fdownload%2Fpostcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha1-jgCcoqOUnNr4rSPmtquZy159KNk=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-unicode/download/postcss-normalize-unicode-4.0.1.tgz?cache=0&sync_timestamp=1597683104480&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-unicode%2Fdownload%2Fpostcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha1-hBvUj9zzAZrUuqdJOj02O1KuHPs=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-url/download/postcss-normalize-url-4.0.1.tgz?cache=0&sync_timestamp=1597682956775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-normalize-url%2Fdownload%2Fpostcss-normalize-url-4.0.1.tgz", - "integrity": "sha1-EOQ3+GvHx+WPe5ZS7YeNqqlfquE=", - "dev": true, - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-whitespace/download/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha1-vx1AcP5Pzqh9E0joJdjMDF+qfYI=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-ordered-values/download/postcss-ordered-values-4.1.2.tgz?cache=0&sync_timestamp=1597682957024&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-ordered-values%2Fdownload%2Fpostcss-ordered-values-4.1.2.tgz", - "integrity": "sha1-DPdcgg7H1cTSgBiVWeC1ceusDu4=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-reduce-initial/download/postcss-reduce-initial-4.0.3.tgz?cache=0&sync_timestamp=1597682957212&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-reduce-initial%2Fdownload%2Fpostcss-reduce-initial-4.0.3.tgz", - "integrity": "sha1-f9QuvqXpyBRgljniwuhK4nC6SN8=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-reduce-transforms/download/postcss-reduce-transforms-4.0.2.tgz?cache=0&sync_timestamp=1597682957300&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-reduce-transforms%2Fdownload%2Fpostcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha1-F++kBerMbge+NBSlyi0QdGgdTik=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-selector-parser": { - "version": "6.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-6.0.2.tgz", - "integrity": "sha1-k0z3mdAWyDQRhZ4J3Oyt4BKG7Fw=", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "postcss-svgo": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-svgo/download/postcss-svgo-4.0.2.tgz?cache=0&sync_timestamp=1597682957408&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-svgo%2Fdownload%2Fpostcss-svgo-4.0.2.tgz", - "integrity": "sha1-F7mXvHEbMzurFDqu07jT1uPTglg=", - "dev": true, - "requires": { - "is-svg": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-unique-selectors/download/postcss-unique-selectors-4.0.1.tgz?cache=0&sync_timestamp=1597682957541&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-unique-selectors%2Fdownload%2Fpostcss-unique-selectors-4.0.1.tgz", - "integrity": "sha1-lEaRHzKJv9ZMbWgPBzwDsfnuS6w=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - } - }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-4.1.0.tgz", - "integrity": "sha1-RD9qIM7WSBor2k+oUypuVdeJoss=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/prepend-http/download/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npm.taobao.org/prettier/download/prettier-1.19.1.tgz?cache=0&sync_timestamp=1589682761987&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fprettier%2Fdownload%2Fprettier-1.19.1.tgz", - "integrity": "sha1-99f1/4qc2HKnvkyhQglZVqYHl8s=", - "dev": true, - "optional": true - }, - "pretty-error": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/pretty-error/download/pretty-error-2.1.1.tgz", - "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", - "dev": true, - "requires": { - "renderkid": "^2.0.1", - "utila": "~0.4" - } - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npm.taobao.org/process/download/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz", - "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz", - "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.6.tgz", - "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", - "dev": true, - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz", - "integrity": "sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ=", - "dev": true - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/public-encrypt/download/public-encrypt-4.0.3.tgz", - "integrity": "sha1-T8ydd6B+SLp1J+fL4N4z0HATMeA=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", - "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/pumpify/download/pumpify-1.5.1.tgz", - "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/pump/download/pump-2.0.1.tgz", - "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz?cache=0&sync_timestamp=1589682803838&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpunycode%2Fdownload%2Fpunycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/q/download/q-1.5.1.tgz?cache=0&sync_timestamp=1589682817412&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fq%2Fdownload%2Fq-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz", - "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", - "dev": true - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npm.taobao.org/query-string/download/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/querystring/download/querystring-0.2.0.tgz?cache=0&sync_timestamp=1589682791876&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquerystring%2Fdownload%2Fquerystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/querystring-es3/download/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/querystringify/download/querystringify-2.2.0.tgz?cache=0&sync_timestamp=1597686771604&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquerystringify%2Fdownload%2Fquerystringify-2.2.0.tgz", - "integrity": "sha1-M0WUG0FTy50ILY7uTNogFqmu9/Y=", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz", - "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/randomfill/download/randomfill-1.0.4.tgz", - "integrity": "sha1-ySGW/IarQr6YPxvzF3giSTHWFFg=", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/range-parser/download/range-parser-1.2.1.tgz", - "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", - "dev": true - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.0.tgz", - "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", - "dev": true, - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-5.2.0.tgz?cache=0&sync_timestamp=1589682810106&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fread-pkg%2Fdownload%2Fread-pkg-5.2.0.tgz", - "integrity": "sha1-e/KVQ4yloz5WzTDgU7NO5yUMk8w=", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz?cache=0&sync_timestamp=1589682741447&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-2.3.7.tgz", - "integrity": "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-3.4.0.tgz", - "integrity": "sha1-n9zN+ekVWAVEkiGsZF6DA6tbmto=", - "dev": true, - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npm.taobao.org/rechoir/download/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/regenerate/download/regenerate-1.4.1.tgz", - "integrity": "sha1-ytkq2Oa1kXc0hfvgWkhcr09Ffm8=", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npm.taobao.org/regenerate-unicode-properties/download/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha1-5d5xEdZV57pgwFfb6f83yH5lzew=", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.7.tgz?cache=0&sync_timestamp=1595456311465&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.7.tgz", - "integrity": "sha1-ysLazIoepnX+qrrriugziYrkb1U=", - "dev": true - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npm.taobao.org/regenerator-transform/download/regenerator-transform-0.14.5.tgz", - "integrity": "sha1-yY2hVGg2ccnE3LFuznNlF+G3/rQ=", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/regex-not/download/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/regexp.prototype.flags/download/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha1-erqJs8E6ZFCdq888qNn7ub31y3U=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/regexpp/download/regexpp-2.0.1.tgz", - "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", - "dev": true - }, - "regexpu-core": { - "version": "4.7.0", - "resolved": "https://registry.npm.taobao.org/regexpu-core/download/regexpu-core-4.7.0.tgz", - "integrity": "sha1-/L9FjFBDGwu3tF1pZ7gZLZHz2Tg=", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npm.taobao.org/regjsgen/download/regjsgen-0.5.2.tgz", - "integrity": "sha1-kv8pX7He7L9uzaslQ9IH6RqjNzM=", - "dev": true - }, - "regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npm.taobao.org/regjsparser/download/regjsparser-0.6.4.tgz", - "integrity": "sha1-p2n4aEMIQBpm6bUp0kNv9NBmYnI=", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npm.taobao.org/jsesc/download/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "renderkid": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/renderkid/download/renderkid-2.0.3.tgz", - "integrity": "sha1-OAF5wv9a4TZcUivy/Pz/AcW3QUk=", - "dev": true, - "requires": { - "css-select": "^1.1.0", - "dom-converter": "^0.2", - "htmlparser2": "^3.3.0", - "strip-ansi": "^3.0.0", - "utila": "^0.4.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/css-select/download/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "dev": true, - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/css-what/download/css-what-2.1.3.tgz", - "integrity": "sha1-ptdgRXM2X+dGhsPzEcVlE9iChfI=", - "dev": true - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/domutils/download/domutils-1.5.1.tgz?cache=0&sync_timestamp=1597680509643&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomutils%2Fdownload%2Fdomutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz", - "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npm.taobao.org/request/download/request-2.88.2.tgz?cache=0&sync_timestamp=1589682741998&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frequest%2Fdownload%2Frequest-2.88.2.tgz", - "integrity": "sha1-1zyRhzHLWofaBH4gcjQUb2ZNErM=", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-2.0.0.tgz", - "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npm.taobao.org/resolve/download/resolve-1.17.0.tgz?cache=0&sync_timestamp=1589682751623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fresolve%2Fdownload%2Fresolve-1.17.0.tgz", - "integrity": "sha1-sllBtUloIxzC0bt2p5y38sC/hEQ=", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/resolve-url/download/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", - "dev": true - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npm.taobao.org/retry/download/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/rgb-regex/download/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/rgba-regex/download/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-2.7.1.tgz?cache=0&sync_timestamp=1589682814592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.7.1.tgz", - "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/ripemd160/download/ripemd160-2.0.2.tgz", - "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npm.taobao.org/run-async/download/run-async-2.4.1.tgz", - "integrity": "sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU=", - "dev": true - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/run-queue/download/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, - "requires": { - "aproba": "^1.1.1" - } - }, - "rxjs": { - "version": "6.6.2", - "resolved": "https://registry.npm.taobao.org/rxjs/download/rxjs-6.6.2.tgz", - "integrity": "sha1-gJanrAPyzE/lhg725XKBDZ4BwNI=", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589682795646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/safe-regex/download/safe-regex-1.1.0.tgz?cache=0&sync_timestamp=1589682757445&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-regex%2Fdownload%2Fsafe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz?cache=0&sync_timestamp=1589682784154&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafer-buffer%2Fdownload%2Fsafer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", - "dev": true - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.7.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-2.7.0.tgz", - "integrity": "sha1-FxUfdtjq5n+793lgwzxnatn078c=", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selfsigned": { - "version": "1.10.7", - "resolved": "https://registry.npm.taobao.org/selfsigned/download/selfsigned-1.10.7.tgz", - "integrity": "sha1-2lgZ/QSdVXTyjoipvMbbxubzkGs=", - "dev": true, - "requires": { - "node-forge": "0.9.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", - "dev": true - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npm.taobao.org/send/download/send-0.17.1.tgz", - "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz?cache=0&sync_timestamp=1590635592890&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime%2Fdownload%2Fmime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz", - "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-4.0.0.tgz", - "integrity": "sha1-tSXhI4SJpez8Qq+sw/6Z5mb0sao=", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/serve-index/download/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz?cache=0&sync_timestamp=1593407858306&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", - "dev": true - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.14.1.tgz", - "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/set-value/download/set-value-2.0.1.tgz", - "integrity": "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/setimmediate/download/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz", - "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npm.taobao.org/sha.js/download/sha.js-2.4.11.tgz", - "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npm.taobao.org/shell-quote/download/shell-quote-1.7.2.tgz?cache=0&sync_timestamp=1589682755902&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshell-quote%2Fdownload%2Fshell-quote-1.7.2.tgz", - "integrity": "sha1-Z6fQLHbJ2iT5nSCAj8re0ODgS+I=", - "dev": true - }, - "shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npm.taobao.org/shelljs/download/shelljs-0.8.4.tgz?cache=0&sync_timestamp=1589684087110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshelljs%2Fdownload%2Fshelljs-0.8.4.tgz", - "integrity": "sha1-3naE/ut2f4cWsyYHiooAh1iQ48I=", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.3.tgz?cache=0&sync_timestamp=1589682814780&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsignal-exit%2Fdownload%2Fsignal-exit-3.0.3.tgz", - "integrity": "sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw=", - "dev": true - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npm.taobao.org/simple-swizzle/download/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.3.2.tgz", - "integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=", - "dev": true - } - } - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/slash/download/slash-2.0.0.tgz?cache=0&sync_timestamp=1589682715547&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslash%2Fdownload%2Fslash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/slice-ansi/download/slice-ansi-2.1.0.tgz", - "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npm.taobao.org/snapdragon/download/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/snapdragon-util/download/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "sockjs": { - "version": "0.3.20", - "resolved": "https://registry.npm.taobao.org/sockjs/download/sockjs-0.3.20.tgz", - "integrity": "sha1-smooPsVi74smh7RAM6Tuzqx12FU=", - "dev": true, - "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.4.0", - "websocket-driver": "0.6.5" - } - }, - "sockjs-client": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/sockjs-client/download/sockjs-client-1.4.0.tgz?cache=0&sync_timestamp=1596410219305&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsockjs-client%2Fdownload%2Fsockjs-client-1.4.0.tgz", - "integrity": "sha1-yfJWjhnI/YFztJl+o0IOC7MGx9U=", - "dev": true, - "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.6.tgz", - "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "faye-websocket": { - "version": "0.11.3", - "resolved": "https://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.11.3.tgz", - "integrity": "sha1-XA6aiWjokSwoZjn96XeosgnyUI4=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - } - } - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/sort-keys/download/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz", - "integrity": "sha1-OZO9hzv8SEecyp6jpUeDXHwVSzQ=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npm.taobao.org/source-map-resolve/download/source-map-resolve-0.5.3.tgz", - "integrity": "sha1-GQhmvs51U+H48mei7oLGBrVQmho=", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npm.taobao.org/source-map-support/download/source-map-support-0.5.19.tgz?cache=0&sync_timestamp=1589682814927&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.5.19.tgz", - "integrity": "sha1-qYti+G3K9PZzmWSMCFKRq56P7WE=", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npm.taobao.org/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz", - "integrity": "sha1-6oBL2UhXQC5pktBaOO8a41qatMQ=", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/spdx-correct/download/spdx-correct-3.1.1.tgz", - "integrity": "sha1-3s6BrJweZxPl99G28X1Gj6U9iak=", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/spdx-exceptions/download/spdx-exceptions-2.3.0.tgz", - "integrity": "sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0=", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/spdx-expression-parse/download/spdx-expression-parse-3.0.1.tgz?cache=0&sync_timestamp=1589682794533&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fspdx-expression-parse%2Fdownload%2Fspdx-expression-parse-3.0.1.tgz", - "integrity": "sha1-z3D1BILu/cmOPOCmgz5KU87rpnk=", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npm.taobao.org/spdx-license-ids/download/spdx-license-ids-3.0.5.tgz", - "integrity": "sha1-NpS1gEVnpFjTyARYQqY1hjL2JlQ=", - "dev": true - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/spdy/download/spdy-4.0.2.tgz", - "integrity": "sha1-t09GYgOj7aRSwCSSuR+56EonZ3s=", - "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/spdy-transport/download/spdy-transport-3.0.0.tgz", - "integrity": "sha1-ANSGOmQArXXfkzYaFghgXl3NzzE=", - "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz?cache=0&sync_timestamp=1589682741447&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/split-string/download/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz", - "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npm.taobao.org/ssri/download/ssri-6.0.1.tgz", - "integrity": "sha1-KjxBso3UW2K2Nnbst0ABJlrp7dg=", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npm.taobao.org/stable/download/stable-0.1.8.tgz", - "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", - "dev": true - }, - "stackframe": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/stackframe/download/stackframe-1.2.0.tgz", - "integrity": "sha1-UkKUktY8YuuYmATBFVLj0i53kwM=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1589682739548&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/stream-browserify/download/stream-browserify-2.0.2.tgz", - "integrity": "sha1-h1IdOKRKp+6RzhzSpH3wy0ndZgs=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npm.taobao.org/stream-each/download/stream-each-1.2.3.tgz", - "integrity": "sha1-6+J6DDibBPvMIzZClS4Qcxr6m64=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npm.taobao.org/stream-http/download/stream-http-2.8.3.tgz", - "integrity": "sha1-stJCRpKIpaJ+xP6JM6z2I95lFPw=", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.1.tgz", - "integrity": "sha1-1wiCgVWasneEJCebCHfaPDktWj0=", - "dev": true - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true - }, - "string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/string-hash/download/string-hash-1.1.3.tgz", - "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.0.tgz", - "integrity": "sha1-lSGCxGzHssMT0VluYjmSvRY7crU=", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/string.prototype.trimend/download/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha1-hYEqa4R6wAInD1gIFGBkyZX7aRM=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/string.prototype.trimstart/download/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha1-FK9tnzSwU/fPyJty+PLuFLkDmlQ=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz", - "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz", - "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", - "dev": true - } - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/strip-final-newline/download/strip-final-newline-2.0.0.tgz", - "integrity": "sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0=", - "dev": true - }, - "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/strip-indent/download/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.1.tgz?cache=0&sync_timestamp=1594567532500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-3.1.1.tgz", - "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=", - "dev": true - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/stylehacks/download/stylehacks-4.0.3.tgz", - "integrity": "sha1-Zxj8r00eB9ihMYaQiB6NlnJqcdU=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/svg-tags/download/svg-tags-1.0.0.tgz", - "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", - "dev": true - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/svgo/download/svgo-1.3.2.tgz", - "integrity": "sha1-ttxRHAYzRsnkFbgeQ0ARRbltQWc=", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npm.taobao.org/table/download/table-5.4.6.tgz", - "integrity": "sha1-EpLRlQDOP4YFOwXw6Ofko7shB54=", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz", - "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/tapable/download/tapable-1.1.3.tgz", - "integrity": "sha1-ofzMBrWNth/XpF2i2kT186Pme6I=", - "dev": true - }, - "terser": { - "version": "4.8.0", - "resolved": "https://registry.npm.taobao.org/terser/download/terser-4.8.0.tgz?cache=0&sync_timestamp=1597761636364&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser%2Fdownload%2Fterser-4.8.0.tgz", - "integrity": "sha1-YwVjQ9fHC7KfOvZlhlpG/gOg3xc=", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-1.4.5.tgz?cache=0&sync_timestamp=1597229593156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-1.4.5.tgz", - "integrity": "sha1-oheu+uozDnNP+sthIOwfoxLWBAs=", - "dev": true, - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/text-table/download/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/thenify/download/thenify-3.3.1.tgz", - "integrity": "sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8=", - "dev": true, - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "dev": true, - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "thread-loader": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/thread-loader/download/thread-loader-2.1.3.tgz", - "integrity": "sha1-y9LBOfwrLebp0o9iKGq3cMGsvdo=", - "dev": true, - "requires": { - "loader-runner": "^2.3.1", - "loader-utils": "^1.1.0", - "neo-async": "^2.6.0" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npm.taobao.org/through2/download/through2-2.0.5.tgz", - "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/thunky/download/thunky-1.1.0.tgz", - "integrity": "sha1-Wrr3FKlAXbBQRzK7zNLO3Z75U30=", - "dev": true - }, - "timers-browserify": { - "version": "2.0.11", - "resolved": "https://registry.npm.taobao.org/timers-browserify/download/timers-browserify-2.0.11.tgz", - "integrity": "sha1-gAsfPu4nLlvFPuRloE0OgEwxIR8=", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz?cache=0&sync_timestamp=1589684134816&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftmp%2Fdownload%2Ftmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/to-object-path/download/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/to-regex/download/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", - "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", - "dev": true - }, - "toposort": { - "version": "1.0.7", - "resolved": "https://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz", - "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", - "dev": true - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.5.0.tgz?cache=0&sync_timestamp=1589682815640&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftough-cookie%2Fdownload%2Ftough-cookie-2.5.0.tgz", - "integrity": "sha1-zZ+yoKodWhK0c72fuW+j3P9lreI=", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/tryer/download/tryer-1.0.1.tgz", - "integrity": "sha1-8shUBoALmw90yfdGW4HqrSQSUvg=", - "dev": true - }, - "ts-pnp": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/ts-pnp/download/ts-pnp-1.2.0.tgz", - "integrity": "sha1-pQCtCEsHmPHDBxrzkeZZEshrypI=", - "dev": true - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-1.13.0.tgz?cache=0&sync_timestamp=1596753875166&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftslib%2Fdownload%2Ftslib-1.13.0.tgz", - "integrity": "sha1-yIHhPMcBWJTtkUhi0nZDb6mkcEM=", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npm.taobao.org/tty-browserify/download/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz?cache=0&sync_timestamp=1589682745749&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftweetnacl%2Fdownload%2Ftweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npm.taobao.org/type-check/download/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npm.taobao.org/type-fest/download/type-fest-0.6.0.tgz", - "integrity": "sha1-jSojcNPfiG61yQraHFv2GIrPg4s=", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz", - "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npm.taobao.org/uglify-js/download/uglify-js-3.4.10.tgz?cache=0&sync_timestamp=1596387201241&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuglify-js%2Fdownload%2Fuglify-js-3.4.10.tgz", - "integrity": "sha1-mtlWPY6zrN+404WX0q8dgV9qdV8=", - "dev": true, - "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.19.0.tgz", - "integrity": "sha1-9hmKqE5bg8RgVLlN3tv+1e6f8So=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/unicode-canonical-property-names-ecmascript/download/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha1-JhmADEyCWADv3YNDr33Zkzy+KBg=", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/unicode-match-property-ecmascript/download/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha1-jtKjJWmWG86SJ9Cc0/+7j+1fAgw=", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/unicode-match-property-value-ecmascript/download/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha1-DZH2AO7rMJaqlisdb8iIduZOpTE=", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/unicode-property-aliases-ecmascript/download/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha1-3Vepn2IHvt/0Yoq++5TFDblByPQ=", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/union-value/download/union-value-1.0.1.tgz", - "integrity": "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/uniq/download/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/uniqs/download/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/unique-filename/download/unique-filename-1.1.1.tgz", - "integrity": "sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA=", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/unique-slug/download/unique-slug-2.0.2.tgz", - "integrity": "sha1-uqvOkQg/xk6UWw861hPiZPfNTmw=", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz", - "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz?cache=0&sync_timestamp=1589682745059&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funpipe%2Fdownload%2Funpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/unquote/download/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/upath/download/upath-1.2.0.tgz", - "integrity": "sha1-j2bbzVWog6za5ECK+LA1pQRMGJQ=", - "dev": true - }, - "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/upper-case/download/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npm.taobao.org/url/download/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-1.3.2.tgz?cache=0&sync_timestamp=1589682803838&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpunycode%2Fdownload%2Fpunycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "url-loader": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/url-loader/download/url-loader-2.3.0.tgz", - "integrity": "sha1-4OLvZY8APvuMpBsPP/v3a6uIZYs=", - "dev": true, - "requires": { - "loader-utils": "^1.2.3", - "mime": "^2.4.4", - "schema-utils": "^2.5.0" - } - }, - "url-parse": { - "version": "1.4.7", - "resolved": "https://registry.npm.taobao.org/url-parse/download/url-parse-1.4.7.tgz", - "integrity": "sha1-qKg1NejACjFuQDpdtKwbm4U64ng=", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/use/download/use-3.1.1.tgz", - "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", - "dev": true - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npm.taobao.org/util/download/util-0.11.1.tgz", - "integrity": "sha1-MjZzNyDsZLsn9uJvQhqqLhtYjWE=", - "dev": true, - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.1.tgz?cache=0&sync_timestamp=1589682767473&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil.promisify%2Fdownload%2Futil.promisify-1.0.1.tgz", - "integrity": "sha1-a693dLgO6w91INi4HQeYKlmruu4=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/utila/download/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/uuid/download/uuid-3.4.0.tgz?cache=0&sync_timestamp=1595885088251&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.4.0.tgz", - "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/v8-compile-cache/download/v8-compile-cache-2.1.1.tgz", - "integrity": "sha1-VLw83UMxe8qR413K8wWxpyN950U=", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npm.taobao.org/validate-npm-package-license/download/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "vendors": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/vendors/download/vendors-1.0.4.tgz", - "integrity": "sha1-4rgApT56Kbk1BsPPQRANFsTErY4=", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/vm-browserify/download/vm-browserify-1.1.2.tgz?cache=0&sync_timestamp=1589682787766&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvm-browserify%2Fdownload%2Fvm-browserify-1.1.2.tgz", - "integrity": "sha1-eGQcSIuObKkadfUR56OzKobl3aA=", - "dev": true - }, - "vue": { - "version": "3.0.0-rc.5", - "resolved": "https://registry.npm.taobao.org/vue/download/vue-3.0.0-rc.5.tgz?cache=0&sync_timestamp=1595983987853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue%2Fdownload%2Fvue-3.0.0-rc.5.tgz", - "integrity": "sha1-lzF11FqJKzvSPvXef6pK3ZxmJ18=", - "requires": { - "@vue/compiler-dom": "3.0.0-rc.5", - "@vue/runtime-dom": "3.0.0-rc.5", - "@vue/shared": "3.0.0-rc.5" - } - }, - "vue-cli-plugin-vuetify": { - "version": "2.0.7", - "resolved": "https://registry.npm.taobao.org/vue-cli-plugin-vuetify/download/vue-cli-plugin-vuetify-2.0.7.tgz", - "integrity": "sha1-/LTxZV58kZnuQNy/ZGXiNV/QdNU=", - "dev": true, - "requires": { - "null-loader": "^3.0.0", - "semver": "^7.1.2", - "shelljs": "^0.8.3" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.2.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.2.tgz", - "integrity": "sha1-YElisFK4HtB4aq6EOJ/7pw/9OTg=", - "dev": true - } - } - }, - "vue-eslint-parser": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.1.0.tgz?cache=0&sync_timestamp=1589684321779&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-eslint-parser%2Fdownload%2Fvue-eslint-parser-7.1.0.tgz", - "integrity": "sha1-nNvMgj5lawh1B6GRFzK4Z6wQHoM=", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-scope": "^5.0.0", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.2.1", - "esquery": "^1.0.1", - "lodash": "^4.17.15" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-5.1.0.tgz?cache=0&sync_timestamp=1591269986906&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-5.1.0.tgz", - "integrity": "sha1-0Plx3+WcaeDK2mhLI9Sdv4JgDOU=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - } - } - }, - "vue-hot-reload-api": { - "version": "2.3.4", - "resolved": "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz?cache=0&sync_timestamp=1589682714858&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-hot-reload-api%2Fdownload%2Fvue-hot-reload-api-2.3.4.tgz", - "integrity": "sha1-UylVzB6yCKPZkLOp+acFdGV+CPI=", - "dev": true - }, - "vue-loader": { - "version": "15.9.3", - "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-15.9.3.tgz", - "integrity": "sha1-DeNdnlVdPtU5aVFsrFziVTEpndo=", - "dev": true, - "requires": { - "@vue/component-compiler-utils": "^3.1.0", - "hash-sum": "^1.0.2", - "loader-utils": "^1.1.0", - "vue-hot-reload-api": "^2.3.0", - "vue-style-loader": "^4.1.0" - }, - "dependencies": { - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - } - } - }, - "vue-loader-v16": { - "version": "npm:vue-loader@16.0.0-beta.5", - "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.0.0-beta.5.tgz", - "integrity": "sha1-BO3IiUkrA6RF56xm6SJqcBdcqKA=", - "dev": true, - "optional": true, - "requires": { - "@types/mini-css-extract-plugin": "^0.9.1", - "chalk": "^3.0.0", - "hash-sum": "^2.0.0", - "loader-utils": "^1.2.3", - "merge-source-map": "^1.1.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "optional": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-3.0.0.tgz", - "integrity": "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ=", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true, - "optional": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true, - "optional": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true, - "optional": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "vue-style-loader": { - "version": "4.1.2", - "resolved": "https://registry.npm.taobao.org/vue-style-loader/download/vue-style-loader-4.1.2.tgz", - "integrity": "sha1-3t80mAbyXOtOZPOtfApE+6c1/Pg=", - "dev": true, - "requires": { - "hash-sum": "^1.0.2", - "loader-utils": "^1.0.2" - }, - "dependencies": { - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - } - } - }, - "vue-template-es2015-compiler": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/vue-template-es2015-compiler/download/vue-template-es2015-compiler-1.9.1.tgz", - "integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=", - "dev": true - }, - "watchpack": { - "version": "1.7.4", - "resolved": "https://registry.npm.taobao.org/watchpack/download/watchpack-1.7.4.tgz?cache=0&sync_timestamp=1597081659128&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwatchpack%2Fdownload%2Fwatchpack-1.7.4.tgz", - "integrity": "sha1-bp2lOzyAuy1lCBiPWyAEEIZs0ws=", - "dev": true, - "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.0" - } - }, - "watchpack-chokidar2": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/watchpack-chokidar2/download/watchpack-chokidar2-2.0.0.tgz", - "integrity": "sha1-mUihhmy71suCTeoTp+1pH2yN3/A=", - "dev": true, - "optional": true, - "requires": { - "chokidar": "^2.1.8" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-2.0.0.tgz", - "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", - "dev": true, - "optional": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "optional": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.13.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-1.13.1.tgz", - "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", - "dev": true, - "optional": true - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-2.1.8.tgz", - "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", - "dev": true, - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.13.tgz", - "integrity": "sha1-8yXLBFVZJCi88Rs4M3DvcOO/zDg=", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz", - "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - } - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npm.taobao.org/wbuf/download/wbuf-1.7.3.tgz", - "integrity": "sha1-wdjRSTFtPqhShIiVy2oL/oh7h98=", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/wcwidth/download/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "webpack": { - "version": "4.44.1", - "resolved": "https://registry.npm.taobao.org/webpack/download/webpack-4.44.1.tgz?cache=0&sync_timestamp=1597430610874&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack%2Fdownload%2Fwebpack-4.44.1.tgz", - "integrity": "sha1-F+af/58yG48RfR/acU7fwLk5zCE=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.3.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "webpack-bundle-analyzer": { - "version": "3.8.0", - "resolved": "https://registry.npm.taobao.org/webpack-bundle-analyzer/download/webpack-bundle-analyzer-3.8.0.tgz", - "integrity": "sha1-zms/kI2vBp/R9yZvaSy7O97ZuhY=", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1", - "bfj": "^6.1.1", - "chalk": "^2.4.1", - "commander": "^2.18.0", - "ejs": "^2.6.1", - "express": "^4.16.3", - "filesize": "^3.6.1", - "gzip-size": "^5.0.0", - "lodash": "^4.17.15", - "mkdirp": "^0.5.1", - "opener": "^1.5.1", - "ws": "^6.0.0" - }, - "dependencies": { - "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-7.4.0.tgz?cache=0&sync_timestamp=1597235774928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-7.4.0.tgz", - "integrity": "sha1-4a1IbmxUUBY0xsOXxcEh2qODYHw=", - "dev": true - } - } - }, - "webpack-chain": { - "version": "6.5.1", - "resolved": "https://registry.npm.taobao.org/webpack-chain/download/webpack-chain-6.5.1.tgz?cache=0&sync_timestamp=1595814928534&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-chain%2Fdownload%2Fwebpack-chain-6.5.1.tgz", - "integrity": "sha1-TycoTLu2N+PI+970Pu9YjU2GEgY=", - "dev": true, - "requires": { - "deepmerge": "^1.5.2", - "javascript-stringify": "^2.0.1" - } - }, - "webpack-dev-middleware": { - "version": "3.7.2", - "resolved": "https://registry.npm.taobao.org/webpack-dev-middleware/download/webpack-dev-middleware-3.7.2.tgz?cache=0&sync_timestamp=1594744455919&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-dev-middleware%2Fdownload%2Fwebpack-dev-middleware-3.7.2.tgz", - "integrity": "sha1-ABnD23FuP6XOy/ZPKriKdLqzMfM=", - "dev": true, - "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" - } - }, - "webpack-dev-server": { - "version": "3.11.0", - "resolved": "https://registry.npm.taobao.org/webpack-dev-server/download/webpack-dev-server-3.11.0.tgz", - "integrity": "sha1-jxVKO84bz9HMYY705wMniFXn/4w=", - "dev": true, - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", - "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.7", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "0.3.20", - "sockjs-client": "1.4.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-2.0.0.tgz", - "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.13.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-1.13.1.tgz", - "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1589682790492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", - "dev": true - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-2.1.8.tgz", - "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-5.0.0.tgz?cache=0&sync_timestamp=1597608006561&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-5.0.0.tgz", - "integrity": "sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U=", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz", - "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", - "dev": true - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.13.tgz", - "integrity": "sha1-8yXLBFVZJCi88Rs4M3DvcOO/zDg=", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-absolute-url": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/is-absolute-url/download/is-absolute-url-3.0.3.tgz", - "integrity": "sha1-lsaiK2ojkpsR6gr7GDbDatSl1pg=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz", - "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz?cache=0&sync_timestamp=1590789322916&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-5.1.0.tgz", - "integrity": "sha1-H9H2cjXVttD+54EFYAG/tpTAOwk=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npm.taobao.org/yargs/download/yargs-13.3.2.tgz?cache=0&sync_timestamp=1597809611661&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-13.3.2.tgz", - "integrity": "sha1-rX/+/sGqWVZayRX4Lcyzipwxot0=", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-13.1.2.tgz?cache=0&sync_timestamp=1596945681098&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-13.1.2.tgz", - "integrity": "sha1-Ew8JcC667vJlDVTObj5XBvek+zg=", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/webpack-log/download/webpack-log-2.0.0.tgz", - "integrity": "sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8=", - "dev": true, - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "webpack-merge": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/webpack-merge/download/webpack-merge-4.2.2.tgz?cache=0&sync_timestamp=1597767024911&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-merge%2Fdownload%2Fwebpack-merge-4.2.2.tgz", - "integrity": "sha1-onxS6ng9E5iv0gh/VH17nS9DY00=", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npm.taobao.org/webpack-sources/download/webpack-sources-1.4.3.tgz", - "integrity": "sha1-7t2OwLko+/HL/plOItLYkPMwqTM=", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - } - } - }, - "websocket-driver": { - "version": "0.6.5", - "resolved": "https://registry.npm.taobao.org/websocket-driver/download/websocket-driver-0.6.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebsocket-driver%2Fdownload%2Fwebsocket-driver-0.6.5.tgz", - "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", - "dev": true, - "requires": { - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/websocket-extensions/download/websocket-extensions-0.1.4.tgz", - "integrity": "sha1-f4RzvIOd/YdgituV1+sHUhFXikI=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/which/download/which-1.3.1.tgz?cache=0&sync_timestamp=1589682812246&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwhich%2Fdownload%2Fwhich-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz?cache=0&sync_timestamp=1589683603678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fword-wrap%2Fdownload%2Fword-wrap-1.2.3.tgz", - "integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=", - "dev": true - }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npm.taobao.org/worker-farm/download/worker-farm-1.7.0.tgz", - "integrity": "sha1-JqlMU5G7ypJhUgAvabhKS/dy5ag=", - "dev": true, - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz", - "integrity": "sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/write/download/write-1.0.3.tgz", - "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npm.taobao.org/ws/download/ws-6.2.1.tgz?cache=0&sync_timestamp=1593925481882&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fws%2Fdownload%2Fws-6.2.1.tgz", - "integrity": "sha1-RC/fCkftZPWbal2P8TD0dI7VJPs=", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz?cache=0&sync_timestamp=1589682817913&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxtend%2Fdownload%2Fxtend-4.0.2.tgz", - "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/y18n/download/y18n-4.0.0.tgz", - "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms=", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-3.1.1.tgz", - "integrity": "sha1-27fa+b/YusmrRev2ArjLrQ1dCP0=", - "dev": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npm.taobao.org/yargs/download/yargs-15.4.1.tgz?cache=0&sync_timestamp=1597809611661&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-15.4.1.tgz", - "integrity": "sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg=", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz?cache=0&sync_timestamp=1597169842138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - } - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-18.1.3.tgz?cache=0&sync_timestamp=1596945681098&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-18.1.3.tgz", - "integrity": "sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A=", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1589682790492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", - "dev": true - } - } - }, - "yorkie": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0.tgz", - "integrity": "sha1-kkEZEtQ1IU4SxRwq4Qk+VLa7g9k=", - "dev": true, - "requires": { - "execa": "^0.8.0", - "is-ci": "^1.0.10", - "normalize-path": "^1.0.0", - "strip-indent": "^2.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.8.0", - "resolved": "https://registry.npm.taobao.org/execa/download/execa-0.8.0.tgz", - "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-3.0.0.tgz?cache=0&sync_timestamp=1597056502934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-stream%2Fdownload%2Fget-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "normalize-path": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-1.0.0.tgz", - "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - } - } -} diff --git a/sub-store-web/package.json b/sub-store-web/package.json deleted file mode 100644 index d7e10b5c85..0000000000 --- a/sub-store-web/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "sub-store-web", - "version": "0.1.0", - "private": true, - "scripts": { - "serve": "vue-cli-service serve", - "build": "vue-cli-service build", - "lint": "vue-cli-service lint" - }, - "dependencies": { - "core-js": "^3.6.5", - "vue": "^3.0.0-0" - }, - "devDependencies": { - "@vue/cli-plugin-babel": "~4.5.0", - "@vue/cli-plugin-eslint": "~4.5.0", - "@vue/cli-service": "~4.5.0", - "@vue/compiler-sfc": "^3.0.0-0", - "babel-eslint": "^10.1.0", - "eslint": "^6.7.2", - "eslint-plugin-vue": "^7.0.0-0", - "vue-cli-plugin-vuetify": "~2.0.7" - }, - "eslintConfig": { - "root": true, - "env": { - "node": true - }, - "extends": [ - "plugin:vue/vue3-essential", - "eslint:recommended" - ], - "parserOptions": { - "parser": "babel-eslint" - }, - "rules": {} - }, - "browserslist": [ - "> 1%", - "last 2 versions", - "not dead" - ] -} diff --git a/sub-store-web/public/favicon.ico b/sub-store-web/public/favicon.ico deleted file mode 100644 index df36fcfb72..0000000000 Binary files a/sub-store-web/public/favicon.ico and /dev/null differ diff --git a/sub-store-web/public/index.html b/sub-store-web/public/index.html deleted file mode 100644 index 4123528656..0000000000 --- a/sub-store-web/public/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - <%= htmlWebpackPlugin.options.title %> - - - -
- - - diff --git a/sub-store-web/src/App.vue b/sub-store-web/src/App.vue deleted file mode 100644 index 55df315325..0000000000 --- a/sub-store-web/src/App.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - - - diff --git a/sub-store-web/src/assets/logo.png b/sub-store-web/src/assets/logo.png deleted file mode 100644 index f3d2503fc2..0000000000 Binary files a/sub-store-web/src/assets/logo.png and /dev/null differ diff --git a/sub-store-web/src/components/HelloWorld.vue b/sub-store-web/src/components/HelloWorld.vue deleted file mode 100644 index 879051a297..0000000000 --- a/sub-store-web/src/components/HelloWorld.vue +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - diff --git a/sub-store-web/src/main.js b/sub-store-web/src/main.js deleted file mode 100644 index 01433bca2a..0000000000 --- a/sub-store-web/src/main.js +++ /dev/null @@ -1,4 +0,0 @@ -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/sub-store.js b/sub-store.js deleted file mode 100644 index cbd9691b97..0000000000 --- a/sub-store.js +++ /dev/null @@ -1,2420 +0,0 @@ -/** - * Sub-Store v0.1 (Backend only) - * @Author: Peng-YM - * @Description: - * 适用于QX,Loon,Surge的订阅管理工具。 - * - 功能 - * 1. 订阅转换,支持SS, SSR, V2RayN, QX, Loon, Surge格式的互相转换。 - * 2. 节点过滤,重命名,排序等。 - * 3. 订阅拆分,组合。 - */ - -const $ = API("sub-store"); - -// Constants -const SUBS_KEY = "subs"; -const COLLECTIONS_KEY = "collections"; - -// SOME INITIALIZATIONS -if (!$.read(SUBS_KEY)) $.write({}, SUBS_KEY); -if (!$.read(COLLECTIONS_KEY)) $.write({}, COLLECTIONS_KEY); - -// BACKEND API -const $app = express(); - -// subscriptions -$app.get("/download/:name", downloadSub) - -$app.route("/sub/:name") - .get(getSub) - .patch(updateSub) - .delete(deleteSub); - -$app.route("/sub") - .get(getAllSubs) - .post(newSub) - .delete(deleteAllSubs); - -// collections -$app.get("/download/collection/:name", downloadCollection); -$app.route("/collection/:name") - .get(getCollection) - .patch(updateCollection) - .delete(deleteCollection); -$app.route("/collection") - .get(getAllCollections) - .post(newCollection) - .delete(deleteAllCollections); - -$app.all("/", (req, res) => { - res.send("Hello from Sub-Store! Made with ❤️ by Peng-YM.") -}); - -$app.start(); - -// SOME CONSTANTS -const FALL_BACK_TARGET = "Raw"; -const DEFAULT_SUPPORTED_PLATFORMS = { - QX: true, - Loon: true, - Surge: true, - Raw: true -} -const AVAILABLE_FILTERS = { - "Keyword Filter": KeywordFilter, - "Discard Keyword Filter": DiscardKeywordFilter, - "Useless Filter": UselessFilter, - "Region Filter": RegionFilter, - "Regex Filter": RegexFilter, - "Discard Regex Filter": DiscardRegexFilter, - "Type Filter": TypeFilter, - "Script Filter": ScriptFilter -} - -const AVAILABLE_OPERATORS = { - "Set Property Operator": SetPropertyOperator, - "Flag Operator": FlagOperator, - "Sort Operator": SortOperator, - "Keyword Sort Operator": KeywordSortOperator, - "Keyword Rename Operator": KeywordRenameOperator, - "Keyword Delete Operator": KeywordDeleteOperator, - "Regex Rename Operator": RegexRenameOperator, - "Regex Delete Operator": RegexDeleteOperator, - "Script Operator": ScriptOperator -} - -/**************************** API -- Subscriptions ***************************************/ -// download subscription, for APP only -async function downloadSub(req, res) { - const {name} = req.params; - const platform = getPlatformFromHeaders(req.headers); - const allSubs = $.read(SUBS_KEY); - if (allSubs[name]) { - const sub = allSubs[name]; - try { - const output = await parseSub(sub, platform); - res.send(output); - } catch (err) { - $.notify('[Sub-Store]', '❌ 无法获取订阅!', `错误信息:${err}`) - res.status(500).json({ - status: "failed", - message: err - }); - } - } else { - res.status(404).json({ - status: "failed", - message: `订阅${name}不存在!` - }); - } -} - -async function parseSub(sub, platform) { - // download from url - const raw = await $.http.get(sub.url).then(resp => resp.body).catch(err => { - throw new Error(err); - }); - console.log("======================================================================="); - console.log(`Processing subscription: ${sub.name}, target platform ==> ${platform}.`); - const $parser = ProxyParser(platform); - let proxies = $parser.parse(raw); - - // filters - const $filter = ProxyFilter(); - // operators - const $operator = ProxyOperator(); - - for (const item of sub.process || []) { - if (item.type.indexOf("Script") !== -1) { - if (item.args && item.args[0].indexOf("http") !== -1) { - // if this is remote script - item.args[0] = await $.http.get(item.args[0]).then(resp => resp.body).catch(err => { - throw new Error(`Error when downloading remote script: ${item.args[0]}.\n Reason: ${err}`); - }); - } - } - if (item.type.indexOf("Filter") !== -1) { - const filter = AVAILABLE_FILTERS[item.type]; - if (filter) { - $filter.addFilters(filter(...(item.args || []))); - proxies = $filter.process(proxies); - console.log(`Applying filter "${item.type}" with arguments:\n >>> ${item.args || "None"}`); - } - } else if (item.type.indexOf("Operator") !== -1) { - const operator = AVAILABLE_OPERATORS[item.type]; - if (operator) { - $operator.addOperators(operator(...(item.args || []))); - proxies = $operator.process(proxies); - console.log(`Applying operator "${item.type}" with arguments: \n >>> ${item.args || "None"}`); - } - } - } - return $parser.produce(proxies); -} - -// Subscriptions -async function getSub(req, res) { - const {name} = req.params; - const sub = $.read(SUBS_KEY)[name]; - if (sub) { - res.json({ - status: "success", - data: sub - }); - } else { - res.status(404).json({ - status: "failed", - message: `未找到订阅:${name}!` - }); - } -} - -async function newSub(req, res) { - const sub = req.body; - const allSubs = $.read(SUBS_KEY); - if (allSubs[sub.name]) { - res.status(500).json({ - status: "failed", - message: `订阅${sub.name}已存在!` - }); - } - // validate name - if (/^[\w-_]*$/.test(sub.name)) { - allSubs[sub.name] = sub; - $.write(allSubs, SUBS_KEY); - res.status(201).json({ - status: "success", - data: sub - }); - } else { - res.status(500).json({ - status: "failed", - message: `订阅名称 ${sub.name} 中含有非法字符!名称中只能包含英文字母、数字、下划线、横杠。` - }) - } -} - -async function updateSub(req, res) { - const {name} = req.params; - let sub = req.body; - const allSubs = $.read(SUBS_KEY); - if (allSubs[name]) { - const newSub = { - ...allSubs[name], - ...sub - }; - allSubs[name] = newSub; - $.write(allSubs, SUBS_KEY); - res.json({ - status: "success", - data: newSub - }) - } else { - res.status(500).json({ - status: "failed", - message: `订阅${name}不存在,无法更新!` - }); - } -} - -async function deleteSub(req, res) { - const {name} = req.params; - let allSubs = $.read(SUBS_KEY); - delete allSubs[name]; - $.write(allSubs, SUBS_KEY); - res.json({ - status: "success" - }); -} - -async function getAllSubs(req, res) { - const allSubs = $.read(SUBS_KEY); - res.json({ - status: "success", - data: Object.keys(allSubs) - }); -} - -async function deleteAllSubs(req, res) { - $.write({}, SUBS_KEY); - res.json({ - status: "success" - }); -} - -// Collections -async function downloadCollection(req, res) { - const {name} = req.params; - const collection = $.read(COLLECTIONS_KEY)[name]; - const platform = getPlatformFromHeaders(req.headers); - if (collection) { - const subs = collection.subscriptions || []; - const output = await Promise.all(subs.map(async id => { - const sub = $.read(SUBS_KEY)[id]; - try { - return parseSub(sub, platform); - } catch (err) { - console.log(`ERROR when process subscription: ${id}`); - return ""; - } - })); - res.send(output.join("\n")); - } else { - $.notify('[Sub-Store]', `❌ 未找到订阅集:${name}!`) - res.status(404).json({ - status: "failed", - message: `❌ 未找到订阅集:${name}!` - }); - } -} - -async function getCollection(req, res) { - const {name} = req.params; - const collection = $.read(COLLECTIONS_KEY)[name]; - if (collection) { - res.json({ - status: "success", - data: collection - }); - } else { - res.status(404).json({ - status: "failed", - message: `未找到订阅集:${name}!` - }); - } -} - -async function newCollection(req, res) { - const collection = req.body; - const allCol = $.read(COLLECTIONS_KEY); - if (allCol[collection.name]) { - res.status(500).json({ - status: "failed", - message: `订阅集${collection.name}已存在!` - }); - } - // validate name - if (/^[\w-_]*$/.test(collection.name)) { - allCol[collection.name] = collection; - $.write(allCol, COLLECTIONS_KEY); - res.status(201).json({ - status: "success", - data: collection - }); - } else { - res.status(500).json({ - status: "failed", - message: `订阅集名称 ${collection.name} 中含有非法字符!名称中只能包含英文字母、数字、下划线、横杠。` - }) - } -} - -async function updateCollection(req, res) { - const {name} = req.params; - let collection = req.body; - const allCol = $.read(COLLECTIONS_KEY); - if (allCol[name]) { - const newCol = { - ...allCol[name], - ...collection - }; - allCol[name] = newCol; - $.write(allCol, COLLECTIONS_KEY); - res.json({ - status: "success", - data: newCol - }) - } else { - res.status(500).json({ - status: "failed", - message: `订阅集${name}不存在,无法更新!` - }); - } -} - -async function deleteCollection(req, res) { - const {name} = req.params; - let allCol = $.read(COLLECTIONS_KEY); - delete allCol[name]; - $.write(allCol, COLLECTIONS_KEY); - res.json({ - status: "success" - }); -} - -async function getAllCollections(req, res) { - const allCols = $.read(COLLECTIONS_KEY); - res.json({ - status: "success", - data: Object.keys(allCols) - }); -} - -async function deleteAllCollections(req, res) { - $.write({}, COLLECTIONS_KEY); - res.json({ - status: "success" - }); -} - -/**************************** Proxy Handlers ***************************************/ -function ProxyParser(targetPlatform) { - // parser collections - const parsers = []; - const producers = []; - - function addParsers(...args) { - args.forEach(a => parsers.push(a())); - } - - function addProducers(...args) { - args.forEach(a => producers.push(a())) - } - - function parse(raw) { - raw = preprocessing(raw); - const lines = raw.split("\n"); - const result = []; - // convert to json format - for (let line of lines) { - line = line.trim(); - if (line.length === 0) continue; // skip empty line - if (line.startsWith("#")) continue; // skip comments - let matched = false; - for (const p of parsers) { - const {patternTest, func} = p; - - // some lines with weird format may produce errors! - let patternMatched; - try { - patternMatched = patternTest(line); - } catch (err) { - patternMatched = false; - } - - if (patternMatched) { - matched = true; - // run parser safely. - try { - const proxy = func(line); - if (!proxy) { - // failed to parse this line - console.log(`ERROR: parser return nothing for \n${line}\n`); - break; - } - // skip unsupported proxies - // if proxy.supported is undefined, assume that all platforms are supported. - if (typeof proxy.supported === 'undefined' || proxy.supported[targetPlatform]) { - delete proxy.supported; - result.push(proxy); - break; - } - } catch (err) { - console.log(`ERROR: Failed to parse line: \n ${line}\n Reason: ${err}`); - } - } - } - if (!matched) { - console.log(`ERROR: Failed to find a rule to parse line: \n${line}\n`); - } - } - if (result.length === 0) { - throw new Error(`ERROR: Input does not contains any valid node for platform ${targetPlatform}`) - } - return result; - } - - function produce(proxies) { - for (const p of producers) { - if (p.targetPlatform === targetPlatform) { - return proxies.map(proxy => { - try { - return p.output(proxy) - } catch (err) { - console.log(`ERROR: cannot produce proxy: ${JSON.stringify(proxy)}\nReason: ${err}`); - return ""; - } - }).join("\n"); - } - } - throw new Error(`Cannot find any producer for target platform: ${targetPlatform}`); - } - - // preprocess raw input - function preprocessing(raw) { - let output; - if (raw.indexOf("DOCTYPE html") !== -1) { - // HTML format, maybe a wrong URL! - throw new Error("Invalid format HTML!"); - } - // check if content is based64 encoded - const Base64 = new Base64Code(); - const keys = ["dm1lc3M", "c3NyOi8v", "dHJvamFu", "c3M6Ly", "c3NkOi8v"]; - if (keys.some(k => raw.indexOf(k) !== -1)) { - output = Base64.safeDecode(raw); - } else { - output = raw; - } - output = output.split("\n"); - for (let i = 0; i < output.length; i++) { - output[i] = output[i].trim(); // trim lines - } - return output.join("\n"); - } - - // Parsers - addParsers( - // URI format parsers - URI_SS, URI_SSR, URI_VMess, URI_Trojan, - // Quantumult X platform - QX_SS, QX_SSR, QX_VMess, QX_Trojan, QX_Http, - // Loon platform - Loon_SS, Loon_SSR, Loon_VMess, Loon_Trojan, Loon_Http, - // Surge platform - Surge_SS, Surge_VMess, Surge_Trojan, Surge_Http - ); - - // Producers - addProducers( - QX_Producer, Loon_Producer, Surge_Producer, Raw_Producer - ); - - return { - parse, produce - }; -} - -function ProxyFilter() { - const filters = []; - - function addFilters(...args) { - args.forEach(a => filters.push(a)); - } - - // select proxies - function process(proxies) { - let selected = FULL(proxies.length, true); - for (const filter of filters) { - try { - selected = AND(selected, filter.func(proxies)); - } catch (err) { - console.log(`Cannot apply filter ${filter.name}\n Reason: ${err}`); - } - } - return proxies.filter((_, i) => selected[i]) - } - - return { - process, addFilters - } -} - -function ProxyOperator() { - const operators = []; - - function addOperators(...args) { - args.forEach(a => operators.push(a)); - } - - // run all operators - function process(proxies) { - let output = clone(proxies); - for (const op of operators) { - try { - const output_ = op.func(output); - if (output_) output = output_; - } catch (err) { - // print log and skip this operator - console.log(`ERROR: cannot apply operator ${op.name}! Reason: ${err}`); - } - } - return output; - } - - return {addOperators, process} -} - -/**************************** URI Format ***************************************/ -// Parse SS URI format (only supports new SIP002, legacy format is depreciated). -// reference: https://shadowsocks.org/en/spec/SIP002-URI-Scheme.html -function URI_SS() { - const patternTest = (line) => { - return /^ss:\/\//.test(line); - } - const Base64 = new Base64Code(); - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - const func = (line) => { - // parse url - let content = line.split("ss://")[1]; - - const proxy = { - name: decodeURIComponent(line.split("#")[1]), - type: "ss", - supported - } - content = content.split("#")[0]; // strip proxy name - - // handle IPV4 and IPV6 - const serverAndPort = content.match(/@([^\/]*)\//)[1]; - const portIdx = serverAndPort.lastIndexOf(":"); - proxy.server = serverAndPort.substring(0, portIdx); - proxy.port = serverAndPort.substring(portIdx + 1); - - const userInfo = Base64.safeDecode(content.split("@")[0]).split(":"); - proxy.cipher = userInfo[0]; - proxy.password = userInfo[1]; - - // handle obfs - const idx = content.indexOf("?plugin="); - if (idx !== -1) { - const pluginInfo = ("plugin=" + decodeURIComponent(content.split("?plugin=")[1])).split(";"); - const params = {}; - for (const item of pluginInfo) { - const [key, val] = item.split("="); - if (key) params[key] = val || true; // some options like "tls" will not have value - } - switch (params.plugin) { - case 'simple-obfs': - proxy.plugin = 'obfs' - proxy['plugin-opts'] = { - mode: params.obfs, - host: params['obfs-host'] - } - break - case 'v2ray-plugin': - proxy.supported = { - ...DEFAULT_SUPPORTED_PLATFORMS, - Loon: false, - Surge: false - } - proxy.obfs = 'v2ray-plugin' - proxy['plugin-opts'] = { - mode: "websocket", - host: params['obfs-host'], - path: params.path || "" - } - break - default: - throw new Error(`Unsupported plugin option: ${params.plugin}`) - } - } - return proxy; - } - return {patternTest, func}; -} - -// Parse URI SSR format, such as ssr://xxx -function URI_SSR() { - const patternTest = (line) => { - return /^ssr:\/\//.test(line); - } - const Base64 = new Base64Code(); - const supported = { - ...DEFAULT_SUPPORTED_PLATFORMS, - Surge: false - } - - const func = (line) => { - line = Base64.safeDecode(line.split("ssr://")[1]); - - // handle IPV6 & IPV4 format - let splitIdx = line.indexOf(':origin'); - if (splitIdx === -1) { - splitIdx = line.indexOf(":auth_"); - } - const serverAndPort = line.substring(0, splitIdx); - const server = serverAndPort.substring(0, serverAndPort.lastIndexOf(":")); - const port = serverAndPort.substring(serverAndPort.lastIndexOf(":") + 1); - - let params = line.substring(splitIdx + 1).split("/?")[0].split(":"); - let proxy = { - type: "ssr", - server, - port, - protocol: params[0], - cipher: params[1], - obfs: params[2], - password: Base64.safeDecode(params[3]), - supported - } - // get other params - params = {}; - line = line.split("/?")[1].split("&"); - if (line.length > 1) { - for (const item of line) { - const [key, val] = item.split("="); - params[key] = val; - } - } - proxy = { - ...proxy, - name: Base64.safeDecode(params.remarks), - "protocol-param": Base64.safeDecode(params.protoparam).replace(/\s/g, "") || "", - "obfs-param": Base64.safeDecode(params.obfsparam).replace(/\s/g, "") || "" - } - return proxy; - } - - return {patternTest, func}; -} - -// V2rayN URI VMess format -// reference: https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2) -function URI_VMess() { - const patternTest = (line) => { - return /^vmess:\/\//.test(line); - } - const Base64 = new Base64Code(); - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - const func = (line) => { - line = line.split("vmess://")[1]; - const params = JSON.parse(Base64.safeDecode(line)); - const proxy = { - name: params.ps, - type: "vmess", - server: params.add, - port: params.port, - cipher: "auto", // V2rayN has no default cipher! use aes-128-gcm as default. - uuid: params.id, - alterId: params.aid || 0, - tls: JSON.parse(params.tls || "false"), - supported - } - // handle obfs - if (params.net === 'ws') { - proxy.network = 'ws'; - proxy['ws-path'] = params.path; - proxy['ws-headers'] = { - Host: params.host || params.add - } - } - return proxy - } - return {patternTest, func}; -} - -// Trojan URI format -function URI_Trojan() { - const patternTest = (line) => { - return /^trojan:\/\//.test(line); - } - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - const func = (line) => { - // trojan forces to use 443 port - if (line.indexOf(":443") === -1) { - throw new Error("Trojan port should always be 443!"); - } - line = line.split("trojan://")[1]; - const server = line.split("@")[1].split(":443")[0]; - - return { - name: `[Trojan] ${server}`, // trojan uri has no server tag! - type: "trojan", - server, - port: 443, - password: line.split("@")[0], - supported - } - } - return {patternTest, func}; -} - -/**************************** Quantumult X ***************************************/ -function QX_SS() { - const patternTest = (line) => { - return /^shadowsocks\s*=/.test(line.split(",")[0].trim()) && line.indexOf("ssr-protocol") === -1; - }; - const func = (line) => { - const params = getQXParams(line); - const proxy = { - name: params.tag, - type: "ss", - server: params.server, - port: params.port, - cipher: params.method, - password: params.password, - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - supported: clone(DEFAULT_SUPPORTED_PLATFORMS) - }; - // handle obfs options - if (params.obfs) { - proxy["plugin-opts"] = { - host: params['obfs-host'] || proxy.server - }; - switch (params.obfs) { - case "http": - case "tls": - proxy.plugin = "obfs"; - proxy["plugin-opts"].mode = params.obfs; - break; - case "ws": - case "wss": - proxy["plugin-opts"] = { - ...proxy["plugin-opts"], - mode: "websocket", - path: params['obfs-uri'], - tls: params.obfs === 'wss' - } - proxy.plugin = "v2ray-plugin" - // Surge and Loon lack support for v2ray-plugin obfs - proxy.supported.Surge = false - proxy.supported.Loon = false - break; - } - } - return proxy; - }; - return {patternTest, func}; -} - -function QX_SSR() { - const patternTest = (line) => { - return /^shadowsocks\s*=/.test(line.split(",")[0].trim()) && line.indexOf("ssr-protocol") !== -1; - }; - const supported = { - ...DEFAULT_SUPPORTED_PLATFORMS, - Surge: false - } - const func = (line) => { - const params = getQXParams(line); - const proxy = { - name: params.tag, - type: "ssr", - server: params.server, - port: params.port, - cipher: params.method, - password: params.password, - protocol: params["ssr-protocol"], - obfs: "plain", // default obfs - "protocol-param": params['ssr-protocol-param'], - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - supported - } - // handle obfs options - if (params.obfs) { - proxy.obfs = params.obfs; - proxy['obfs-param'] = params['obfs-host'] - } - return proxy; - } - return {patternTest, func}; -} - -function QX_VMess() { - const patternTest = (line) => { - return /^vmess\s*=/.test(line.split(",")[0].trim()); - }; - const func = (line) => { - const params = getQXParams(line) - const proxy = { - type: "vmess", - name: params.tag, - server: params.server, - port: params.port, - cipher: params.method || 'none', - uuid: params.password, - alterId: 0, - tls: params.obfs === 'over-tls' || params.obfs === 'wss', - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - } - if (proxy.tls) { - proxy.sni = params['obfs-host'] || params.server; - proxy.scert = !JSON.parse(params['tls-verification'] || 'true'); - } - // handle ws headers - if (params.obfs === 'ws' || params.obfs === 'wss') { - proxy.network = 'ws'; - proxy['ws-path'] = params['obfs-uri']; - proxy['ws-headers'] = { - Host: params['obfs-host'] || params.server // if no host provided, use the same as server - } - } - return proxy; - } - - return {patternTest, func}; -} - -function QX_Trojan() { - const patternTest = (line) => { - return /^trojan\s*=/.test(line.split(",")[0].trim()); - }; - const func = (line) => { - const params = getQXParams(line); - const proxy = { - type: "trojan", - name: params.tag, - server: params.server, - port: params.port, - password: params.password, - sni: params['tls-host'] || params.server, - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - } - proxy.scert = !JSON.parse(params['tls-verification'] || 'true'); - return proxy; - } - return {patternTest, func} -} - -function QX_Http() { - const patternTest = (line) => { - return /^http\s*=/.test(line.split(",")[0].trim()); - }; - const func = (line) => { - const params = getQXParams(line); - const proxy = { - type: "http", - name: params.tag, - server: params.server, - port: params.port, - username: params.username, - password: params.password, - tls: JSON.parse(params['over-tls'] || "false"), - udp: JSON.parse(params["udp-relay"] || "false"), - tfo: JSON.parse(params["fast-open"] || "false"), - } - if (proxy.tls) { - proxy.sni = params['tls-host'] || proxy.server; - proxy.scert = !JSON.parse(params['tls-verification'] || 'true'); - } - return proxy; - } - - return {patternTest, func}; -} - -function getQXParams(line) { - const groups = line.split(","); - const params = {}; - const protocols = ["shadowsocks", "vmess", "http", "trojan"]; - groups.forEach((g) => { - const [key, value] = g.split("="); - if (protocols.indexOf(key) !== -1) { - params.type = key; - const conf = value.split(":"); - params.server = conf[0]; - params.port = conf[1]; - } else { - params[key.trim()] = value.trim(); - } - }); - return params; -} - -/**************************** Loon ***************************************/ -function Loon_SS() { - const patternTest = (line) => { - return line.split(",")[0].split("=")[1].trim().toLowerCase() === 'shadowsocks'; - } - const func = (line) => { - const params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "ss", - server: params[1], - port: params[2], - cipher: params[3], - password: params[4].replace(/"/g, "") - } - // handle obfs - if (params.length > 5) { - proxy.plugin = 'obfs'; - proxy['plugin-opts'] = { - mode: proxy.obfs, - host: params[6] - } - } - return proxy; - } - return {patternTest, func}; -} - -function Loon_SSR() { - const patternTest = (line) => { - return line.split(",")[0].split("=")[1].trim().toLowerCase() === 'shadowsocksr'; - } - const func = (line) => { - const params = line.split("=")[1].split(","); - const supported = clone(DEFAULT_SUPPORTED_PLATFORMS); - supported.Surge = false; - return { - name: line.split("=")[0].trim(), - type: "ssr", - server: params[1], - port: params[2], - cipher: params[3], - password: params[4].replace(/"/g, ""), - protocol: params[5], - "protocol-param": params[6].match(/{(.*)}/)[1], - supported, - obfs: params[7], - 'obfs-param': params[8].match(/{(.*)}/)[1] - } - } - return {patternTest, func}; -} - -function Loon_VMess() { - const patternTest = (line) => { - // distinguish between surge vmess - return /^.*=\s*vmess/i.test(line.split(",")[0]) && line.indexOf("username") === -1; - } - const func = (line) => { - let params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "vmess", - server: params[1], - port: params[2], - cipher: params[3] || 'none', - uuid: params[4].replace(/"/g, ""), - alterId: 0, - } - // get transport options - params = params.splice(5); - for (const item of params) { - const [key, val] = item.split(":"); - params[key] = val; - } - proxy.tls = JSON.parse(params['over-tls'] || 'false'); - if (proxy.tls) { - proxy.sni = params['tls-name'] || proxy.server; - proxy.scert = JSON.parse(params['skip-cert-verify'] || 'false'); - } - switch (params.transport) { - case "tcp": - break; - case "ws": - proxy.network = params.transport - proxy['ws-path'] = params.path - proxy['ws-headers'] = { - Host: params.host - } - } - if (proxy.tls) { - proxy.scert = JSON.parse(params['skip-cert-verify'] || 'false') - } - return proxy; - } - return {patternTest, func}; -} - -function Loon_Trojan() { - const patternTest = (line) => { - return /^.*=\s*trojan/i.test(line.split(",")[0]) && line.indexOf("password") === -1; - } - - const func = (line) => { - const params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "trojan", - server: params[1], - port: params[2], - password: params[3].replace(/"/g, ""), - sni: params[1], // default sni is the server itself - scert: JSON.parse(params['skip-cert-verify'] || 'false') - } - // trojan sni - if (params.length > 4) { - const [key, val] = params[4].split(":"); - if (key === 'tls-name') proxy.sni = val; - else throw new Error(`ERROR: unknown option ${key} for line: \n${line}`); - } - return proxy; - } - - return {patternTest, func} -} - -function Loon_Http() { - const patternTest = (line) => { - return /^.*=\s*http/i.test(line.split(",")[0]) - && line.split(",").length === 5 - && line.indexOf("username") === -1 - && line.indexOf("password") === -1 - } - - const func = (line) => { - const params = line.split("=")[1].split(","); - const proxy = { - name: line.split("=")[0].trim(), - type: "http", - server: params[1], - port: params[2], - tls: params[2] === "443", // port 443 is considered as https type - username: (params[3] || "").replace(/"/g, ""), - password: (params[4] || "").replace(/"/g, "") - } - if (proxy.tls) { - proxy.sni = params['tls-name'] || proxy.server; - proxy.scert = JSON.parse(params['skip-cert-verify'] || 'false'); - } - - return proxy; - } - return {patternTest, func} -} - -/**************************** Surge ***************************************/ -function Surge_SS() { - const patternTest = (line) => { - return /^.*=\s*ss/.test(line.split(",")[0]); - } - const func = (line) => { - const params = getSurgeParams(line); - const proxy = { - name: params.name, - type: "ss", - server: params.server, - port: params.port, - cipher: params['encrypt-method'], - password: params.password, - tfo: JSON.parse(params.tfo || "false"), - udp: JSON.parse(params['udp-relay'] || "false"), - } - // handle obfs - if (params.obfs) { - proxy.plugin = 'obfs'; - proxy['plugin-opts'] = { - mode: params.obfs, - host: params['obfs-host'] - } - } - return proxy; - } - return {patternTest, func} -} - -function Surge_VMess() { - const patternTest = (line) => { - return /^.*=\s*vmess/.test(line.split(",")[0]) && line.indexOf("username") !== -1; - } - const func = (line) => { - const params = getSurgeParams(line); - const proxy = { - name: params.name, - type: "vmess", - server: params.server, - port: params.port, - uuid: params.username, - alterId: 0, // surge does not have this field - cipher: "none", // surge does not have this field - tls: JSON.parse(params.tls || "false"), - tfo: JSON.parse(params.tfo || "false"), - } - if (proxy.tls) { - proxy.scert = JSON.parse(params['skip-cert-verify'] || "false"); - proxy.sni = params['sni'] || params.server; - } - // use websocket - if (JSON.parse(params.ws || "false")) { - proxy.network = 'ws'; - proxy['ws-path'] = params['ws-path']; - proxy['ws-headers'] = { - Host: params.sni - } - } - return proxy; - } - return {patternTest, func}; -} - -function Surge_Trojan() { - const patternTest = (line) => { - return /^.*=\s*trojan/.test(line.split(",")[0]) && line.indexOf("sni") !== -1; - } - const func = (line) => { - const params = getSurgeParams(line); - return { - name: params.name, - type: "trojan", - server: params.server, - port: params.port, - password: params.password, - sni: params.sni || params.server, - tfo: JSON.parse(params.tfo || "false"), - scert: JSON.parse(params['skip-cert-verify'] || "false"), - } - } - - return {patternTest, func}; -} - -function Surge_Http() { - const patternTest = (line) => { - return /^.*=\s*http/.test(line.split(",")[0]) && !Loon_Http().patternTest(line) - } - const func = (line) => { - const params = getSurgeParams(line); - const proxy = { - name: params.name, - type: "http", - server: params.server, - port: params.port, - tls: JSON.parse(params.tls || "false"), - tfo: JSON.parse(params.tfo || "false"), - } - if (proxy.tls) { - proxy.scert = JSON.parse(params['skip-cert-verify'] || "false"); - proxy.sni = params.sni || params.server; - } - if (params.username !== 'none') proxy.username = params.username; - if (params.password !== 'none') proxy.password = params.password; - return proxy; - } - return {patternTest, func} -} - -function getSurgeParams(line) { - const params = {}; - params.name = line.split("=")[0].trim(); - const segments = line.split(","); - params.server = segments[1].trim(); - params.port = segments[2].trim(); - for (let i = 3; i < segments.length; i++) { - const item = segments[i] - if (item.indexOf("=") !== -1) { - const [key, value] = item.split("="); - params[key.trim()] = value.trim(); - } - } - return params; -} - -/**************************** Output Functions ***************************************/ -function QX_Producer() { - const targetPlatform = "QX"; - const output = (proxy) => { - let obfs_opts; - let tls_opts; - switch (proxy.type) { - case 'ss': - obfs_opts = ""; - if (proxy.plugin === 'obfs') { - obfs_opts = `,obfs=${proxy['plugin-opts'].mode},obfs-host=${proxy['plugin-opts'].host}`; - } - if (proxy.plugin === 'v2ray-plugin') { - const {tls, host, path} = proxy['plugin-opts']; - obfs_opts = `,obfs=${tls ? 'wss' : 'ws'},obfs-host=${host}${path ? ',obfs-uri=' + path : ""}`; - } - return `shadowsocks = ${proxy.server}:${proxy.port}, method=${proxy.cipher}, password=${proxy.password}${obfs_opts}${proxy.tfo ? ", fast-open=true" : ", fast-open=false"}${proxy.udp ? ", udp-relay=true" : ", udp-relay=false"}, tag=${proxy.name}` - case 'ssr': - return `shadowsocks=${proxy.server}:${proxy.port},method=${proxy.cipher},password=${proxy.password},ssr-protocol=${proxy.protocol}${proxy['protocol-param'] ? ",ssr-protocol-param=" + proxy['protocol-param'] : ""}${proxy.obfs ? ",obfs=" + proxy.obfs : ""}${proxy['obfs-param'] ? ",obfs-host=" + proxy['obfs-param'] : ""}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${proxy.udp ? ",udp-relay=true" : ",udp-relay=false"},tag=${proxy.name}` - case 'vmess': - obfs_opts = ""; - if (proxy.network === 'ws') { - // websocket - if (proxy.tls) { - // ws-tls - obfs_opts = `,obfs=wss,obfs-host=${proxy.sni}${proxy['ws-path'] ? ",obfs-uri=" + proxy['ws-path'] : ""},tls-verification=${proxy.scert ? "false" : "true"}`; - } else { - // ws - obfs_opts = `,obfs=ws,obfs-host=${proxy['ws-headers'].Host}${proxy['ws-path'] ? ",obfs-uri=" + proxy['ws-path'] : ""}`; - } - } else { - // tcp - if (proxy.tls) { - obfs_opts = `,obfs=over-tls,obfs-host=${proxy.sni},tls-verification=${proxy.scert ? "false" : "true"}`; - } - } - return `vmess=${proxy.server}:${proxy.port},method=${proxy.cipher},password=${proxy.uuid}${obfs_opts}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${proxy.udp ? ",udp-relay=true" : ",udp-relay=false"},tag=${proxy.name}` - case 'trojan': - return `trojan=${proxy.server}:${proxy.port},password=${proxy.password},tls-host=${proxy.sni},tls-verification=${proxy.scert ? "false" : "true"}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${proxy.udp ? ",udp-relay=true" : ",udp-relay=false"},tag=${proxy.name}` - case 'http': - tls_opts = ""; - if (proxy.tls) { - tls_opts = `,over-tls=true,tls-verification=${proxy.scert ? "false" : "true"},tls-host=${proxy.sni}`; - } - return `http=${proxy.server}:${proxy.port},username=${proxy.username},password=${proxy.password}${tls_opts}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"},tag=${proxy.name}`; - } - throw new Error(`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`); - } - return {targetPlatform, output}; -} - -function Loon_Producer() { - const targetPlatform = "Loon"; - const output = (proxy) => { - let obfs_opts, tls_opts; - switch (proxy.type) { - case "ss": - obfs_opts = ",,"; - if (proxy.plugin === 'obfs') { - const {mode, host} = proxy['plugin-opts']; - obfs_opts = `,${mode},${host}` - } - return `${proxy.name}=shadowsocks,${proxy.server},${proxy.port},${proxy.cipher},${proxy.password}${obfs_opts}`; - case "ssr": - return `${proxy.name}=shadowsocksr,${proxy.server},${proxy.port},${proxy.cipher},${proxy.password},${proxy.protocol},{${proxy['protocol-param']}},${proxy.obfs},{${proxy['obfs-param']}}` - case "vmess": - obfs_opts = ""; - if (proxy.network === 'ws') { - const host = proxy['ws-headers'].Host; - obfs_opts = `,transport:ws,host:${host},path:${proxy['ws-path']}`; - } else { - obfs_opts = `,transport:tcp`; - } - if (proxy.tls) { - obfs_opts += `,tls-name=${proxy.sni},skip-cert-verify:${proxy.scert}`; - } - return `${proxy.name}=vmess,${proxy.server},${proxy.port},${proxy.cipher},over-tls:${proxy.tls}${obfs_opts}`; - case "trojan": - return `${proxy.name}=trojan,${proxy.server},${proxy.port},${proxy.password},tls-name:${proxy.sni},skip-cert-verify:${proxy.scert}`; - case "http": - tls_opts = ""; - const base = `${proxy.name}=${proxy.tls ? 'http' : 'https'},${proxy.server},${proxy.port},${proxy.username || ""},${proxy.password || ""}`; - if (proxy.tls) { - // https - tls_opts = `,skip-cert-verify:${proxy.scert},tls-name:${proxy.sni}`; - return base + tls_opts; - } else return base; - } - throw new Error(`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`); - } - return {targetPlatform, output} -} - -function Surge_Producer() { - const targetPlatform = "Surge"; - const output = (proxy) => { - let obfs_opts, tls_opts; - switch (proxy.type) { - case 'ss': - obfs_opts = ""; - if (proxy.plugin === "obfs") { - obfs_opts = `,obfs=${proxy['plugin-opts'].mode},obfs-host=${proxy['plugin-opts'].host}` - } else { - throw new Error(`Platform ${targetPlatform} does not support obfs option: ${proxy.obfs}`); - } - return `${proxy.name}=ss,${proxy.server},${proxy.port},encrypt-method=${proxy.cipher},password=${proxy.password}${obfs_opts},tfo=${proxy.tfo || 'false'},udp-relay=${proxy.udp || 'false'}`; - case 'vmess': - tls_opts = ""; - let config = `${proxy.name}=vmess,${proxy.server},${proxy.port},username=${proxy.uuid},tls=${proxy.tls},tfo=${proxy.tfo || "false"}`; - if (proxy.network === 'ws') { - const path = proxy['ws-path']; - const host = proxy['ws-headers'].Host; - config += `,ws=true${path ? ',ws-path=' + path : ""}${host ? ',ws-headers=HOST:' + host : ""}`; - } - if (proxy.tls) { - config += `,skip-cert-verify=${proxy.scert},sni=${proxy.sni}`; - } - return config; - case 'trojan': - return `${proxy.name}=trojan,${proxy.server},${proxy.port},password=${proxy.password},sni=${proxy.sni},tfo=${proxy.tfo || 'false'}`; - case 'http': - tls_opts = ",tls=false"; - if (proxy.tls) { - tls_opts = `,tls=true,skip-cert-verify=${proxy.scert},sni=${proxy.sni}`; - } - return `${proxy.name}=http,${proxy.server},${proxy.port}${proxy.username ? ",username=" + proxy.username : ""}${proxy.password ? ",password=" + proxy.password : ""}${tls_opts},tfo=${proxy.tfo || 'false'}`; - } - throw new Error(`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`); - } - return {targetPlatform, output}; -} - -function Raw_Producer() { - const targetPlatform = "Raw"; - const output = (proxy) => { - return JSON.stringify(proxy); - } - return {targetPlatform, output}; -} - -/**************************** Operators ***************************************/ -// force to set some properties (e.g., scert, udp, tfo, etc.) -function SetPropertyOperator(key, val) { - return { - name: "Set Property Operator", - func: proxies => { - return proxies.map(p => { - p[key] = val; - return p; - }) - } - } -} - -// add or remove flag for proxies -function FlagOperator(type) { - return { - name: "Flag Operator", - func: proxies => { - return proxies.map(proxy => { - switch (type) { - case 0: - // no flag - proxy.name = removeFlag(proxy.name); - break - case 1: - // get flag - const newFlag = getFlag(proxy.name); - // remove old flag - proxy.name = removeFlag(proxy.name); - proxy.name = newFlag + " " + proxy.name; - proxy.name = proxy.name.replace(/🇹🇼/g, "🇨🇳"); - break; - default: - throw new Error("Unknown flag type: " + type); - } - return proxy; - }) - } - } -} - -// sort proxies according to their names -function SortOperator(order = 'asc') { - return { - name: "Sort Operator", - func: proxies => { - switch (order) { - case "asc": - case 'desc': - return proxies.sort((a, b) => { - let res = (a.name > b.name) ? 1 : -1; - res *= order === 'desc' ? -1 : 1; - return res - }) - case 'random': - return shuffle(proxies); - default: - throw new Error("Unknown sort option: " + order); - } - } - } -} - -// sort by keywords -function KeywordSortOperator(...keywords) { - return { - name: "Keyword Sort Operator", - func: proxies => proxies.sort((a, b) => { - const oA = getKeywordOrder(keywords, a.name); - const oB = getKeywordOrder(keywords, b.name); - if (oA && !oB) return -1; - if (oB && !oA) return 1; - if (oA && oB) return oA < oB ? -1 : 1; - if ((!oA && !oB) || (oA && oB && oA === oB)) return a.name < b.name ? -1 : 1; // fallback to normal sort - }) - } -} - -function getKeywordOrder(keywords, str) { - let order = null; - for (let i = 0; i < keywords.length; i++) { - if (str.indexOf(keywords[i]) !== -1) { - order = i + 1; // plus 1 is important! 0 will be treated as false!!! - break; - } - } - return order; -} - -// rename by keywords -// keywords: [{old: "old", now: "now"}] -function KeywordRenameOperator(...keywords) { - return { - name: "Keyword Rename Operator", - func: proxies => { - return proxies.map(proxy => { - for (const {old, now} of keywords) { - proxy.name = proxy.name.replace(old, now); - } - return proxy; - }) - } - } -} - -// rename by regex -// keywords: [{expr: "string format regex", now: "now"}] -function RegexRenameOperator(...regex) { - return { - name: "Regex Rename Operator", - func: proxies => { - return proxies.map(proxy => { - for (const {expr, now} of regex) { - proxy.name = proxy.name.replace(new RegExp(expr, "g"), now); - } - return proxy; - }) - } - } -} - -// delete keywords operator -// keywords: ['a', 'b', 'c'] -function KeywordDeleteOperator(...keywords) { - const keywords_ = keywords.map(k => { - return { - old: k, - now: "" - } - }) - return { - name: "Keyword Delete Operator", - func: KeywordRenameOperator(keywords_).func - } -} - -// delete regex operator -// regex: ['a', 'b', 'c'] -function RegexDeleteOperator(...regex) { - const regex_ = regex.map(r => { - return { - expr: r, - now: "" - } - }); - return { - name: "Regex Delete Operator", - func: RegexRenameOperator(regex_).func - } -} - -// use base64 encoded script to rename -/** Example script - function func(proxies) { - // do something - return proxies; - } - - WARNING: - 1. This function name should be `func`! - 2. Always declare variable before using it! - */ -function ScriptOperator(script) { - return { - name: "Script Operator", - func: (proxies) => { - ;(function () { - eval(script); - return func(proxies); - })(); - } - } -} - -/**************************** Filters ***************************************/ -// filter by keywords -function KeywordFilter(...keywords) { - return { - name: "Keyword Filter", - func: (proxies) => { - return proxies.map(proxy => keywords.some(k => proxy.name.indexOf(k) !== -1)); - } - } -} - -function DiscardKeywordFilter(...keywords) { - return { - name: "Discard Keyword Filter", - func: proxies => { - const filter = KeywordFilter(keywords).func; - return NOT(filter(proxies)); - } - } -} - -// filter useless proxies -function UselessFilter() { - const KEYWORDS = ["流量", "时间", "应急", "过期", "Bandwidth", "expire"]; - return { - name: "Useless Filter", - func: DiscardKeywordFilter(KEYWORDS).func - } -} - -// filter by regions -function RegionFilter(...regions) { - const REGION_MAP = { - "HK": "🇭🇰", - "TW": "🇹🇼", - "US": "🇺🇸", - "SG": "🇸🇬", - "JP": "🇯🇵", - "UK": "🇬🇧", - "KR": "🇰🇷" - }; - return { - name: "Region Filter", - func: (proxies) => { - // this would be high memory usage - return proxies.map(proxy => { - const flag = getFlag(proxy.name); - return regions.some(r => REGION_MAP[r] === flag); - }) - } - } -} - -// filter by regex -function RegexFilter(...regex) { - return { - name: "Regex Filter", - func: (proxies) => { - return proxies.map(proxy => regex.some(r => r.test(proxy.name))); - } - } -} - -function DiscardRegexFilter(...regex) { - return { - name: "Discard Regex Filter", - func: proxies => { - const filter = RegexFilter(regex).func; - return NOT(filter(proxies)); - } - } -} - -// filter by proxy types -function TypeFilter(...types) { - return { - name: "Type Filter", - func: (proxies) => { - return proxies.map(proxy => types.some(t => proxy.type === t)); - } - } -} - -// use base64 encoded script to filter proxies -/** Script Example - function func(proxies) { - const selected = FULL(proxies.length, true); - // do something - return selected; - } - WARNING: - 1. This function name should be `func`! - 2. Always declare variable before using it! - */ -function ScriptFilter(script) { - return { - name: "Script Filter", - func: (proxies) => { - !(function () { - eval(script); - return filter(proxies); - })(); - } - } -} - -/******************************** Utility Functions *********************************************/ -// get proxy flag according to its name -function getFlag(name) { - // flags from @KOP-XIAO: https://github.com/KOP-XIAO/QuantumultX/blob/master/Scripts/resource-parser.js - const flags = { - "🏳️‍🌈": ["流量", "时间", "应急", "过期", "Bandwidth", "expire"], - "🇦🇨": ["AC"], - "🇦🇹": ["奥地利", "维也纳"], - "🇦🇺": ["AU", "Australia", "Sydney", "澳大利亚", "澳洲", "墨尔本", "悉尼"], - "🇧🇪": ["BE", "比利时"], - "🇧🇬": ["保加利亚", "Bulgaria"], - "🇧🇷": ["BR", "Brazil", "巴西", "圣保罗"], - "🇨🇦": ["Canada", "Waterloo", "加拿大", "蒙特利尔", "温哥华", "楓葉", "枫叶", "滑铁卢", "多伦多"], - "🇨🇭": ["瑞士", "苏黎世", "Switzerland"], - "🇩🇪": ["DE", "German", "GERMAN", "德国", "德國", "法兰克福"], - "🇩🇰": ["丹麦"], - "🇪🇸": ["ES", "西班牙", "Spain"], - "🇪🇺": ["EU", "欧盟", "欧罗巴"], - "🇫🇮": ["Finland", "芬兰", "赫尔辛基"], - "🇫🇷": ["FR", "France", "法国", "法國", "巴黎"], - "🇬🇧": ["UK", "GB", "England", "United Kingdom", "英国", "伦敦", "英"], - "🇲🇴": ["MO", "Macao", "澳门", "CTM"], - "🇭🇺": ["匈牙利", "Hungary"], - "🇭🇰": ["HK", "Hongkong", "Hong Kong", "香港", "深港", "沪港", "呼港", "HKT", "HKBN", "HGC", "WTT", "CMI", "穗港", "京港", "港"], - "🇮🇩": ["Indonesia", "印尼", "印度尼西亚", "雅加达"], - "🇮🇪": ["Ireland", "爱尔兰", "都柏林"], - "🇮🇳": ["India", "印度", "孟买", "Mumbai"], - "🇰🇵": ["KP", "朝鲜"], - "🇰🇷": ["KR", "Korea", "KOR", "韩国", "首尔", "韩", "韓"], - "🇱🇻": ["Latvia", "Latvija", "拉脱维亚"], - "🇲🇽️": ["MEX", "MX", "墨西哥"], - "🇲🇾": ["MY", "Malaysia", "马来西亚", "吉隆坡"], - "🇳🇱": ["NL", "Netherlands", "荷兰", "荷蘭", "尼德蘭", "阿姆斯特丹"], - "🇵🇭": ["PH", "Philippines", "菲律宾"], - "🇷🇴": ["RO", "罗马尼亚"], - "🇷🇺": ["RU", "Russia", "俄罗斯", "俄羅斯", "伯力", "莫斯科", "圣彼得堡", "西伯利亚", "新西伯利亚", "京俄", "杭俄"], - "🇸🇦": ["沙特", "迪拜"], - "🇸🇪": ["SE", "Sweden"], - "🇸🇬": ["SG", "Singapore", "新加坡", "狮城", "沪新", "京新", "泉新", "穗新", "深新", "杭新", "广新"], - "🇹🇭": ["TH", "Thailand", "泰国", "泰國", "曼谷"], - "🇹🇷": ["TR", "Turkey", "土耳其", "伊斯坦布尔"], - "🇹🇼": ["TW", "Taiwan", "台湾", "台北", "台中", "新北", "彰化", "CHT", "台", "HINET"], - "🇺🇸": ["US", "USA", "America", "United States", "美国", "美", "京美", "波特兰", "达拉斯", "俄勒冈", "凤凰城", "费利蒙", "硅谷", "矽谷", "拉斯维加斯", "洛杉矶", "圣何塞", "圣克拉拉", "西雅图", "芝加哥", "沪美", "哥伦布", "纽约"], - "🇻🇳": ["VN", "越南", "胡志明市"], - "🇮🇹": ["Italy", "IT", "Nachash", "意大利", "米兰", "義大利"], - "🇿🇦": ["South Africa", "南非"], - "🇦🇪": ["United Arab Emirates", "阿联酋"], - "🇯🇵": ["JP", "Japan", "日", "日本", "东京", "大阪", "埼玉", "沪日", "穗日", "川日", "中日", "泉日", "杭日", "深日", "辽日", "广日"], - "🇦🇷": ["AR", "阿根廷"], - "🇳🇴": ["Norway", "挪威", "NO"], - "🇨🇳": ["CN", "China", "回国", "中国", "江苏", "北京", "上海", "广州", "深圳", "杭州", "徐州", "青岛", "宁波", "镇江", "back"] - }; - for (let k of Object.keys(flags)) { - if (flags[k].some((item => name.indexOf(item) !== -1))) { - return k; - } - } - // no flag found - const oldFlag = (name.match(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/) || [])[0]; - return oldFlag || "🏴‍☠️"; -} - -// remove flag -function removeFlag(str) { - return str.replace(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/g, "").trim(); -} - -// clone an object -function clone(obj) { - return JSON.parse(JSON.stringify(obj)) -} - -// shuffle array -function shuffle(array) { - let currentIndex = array.length, temporaryValue, randomIndex; - - // While there remain elements to shuffle... - while (0 !== currentIndex) { - - // Pick a remaining element... - randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex -= 1; - - // And swap it with the current element. - temporaryValue = array[currentIndex]; - array[currentIndex] = array[randomIndex]; - array[randomIndex] = temporaryValue; - } - - return array; -} - -// some logical functions for proxy filters -function AND(...args) { - return args.reduce((a, b) => a.map((c, i) => b[i] && c)); -} - -function OR(...args) { - return args.reduce((a, b) => a.map((c, i) => b[i] || c)) -} - -function NOT(array) { - return array.map(c => !c); -} - -function FULL(length, bool) { - return [...Array(length).keys()].map(() => bool); -} - -// UUID -// source: https://stackoverflow.com/questions/105034/how-to-create-guid-uuid -function UUID() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); -} - -// get platform form UA -function getPlatformFromHeaders(headers) { - const keys = Object.keys(headers); - let UA = ""; - for (let k of keys) { - if (k.match(/USER-AGENT/i)) { - UA = headers[k]; - break; - } - } - if (UA.indexOf("Quantumult%20X") !== -1) { - return "QX"; - } else if (UA.indexOf("Surge") !== -1) { - return "Surge"; - } else if (UA.indexOf("Decar") !== -1) { - return "Loon"; - } else { - // browser - return FALL_BACK_TARGET; - } -} - -/*********************************** OpenAPI *************************************/ -// OpenAPI -// prettier-ignore -function ENV() { - const isQX = typeof $task != "undefined"; - const isLoon = typeof $loon != "undefined"; - const isSurge = typeof $httpClient != "undefined" && !this.isLoon; - const isJSBox = typeof require == "function" && typeof $jsbox != "undefined"; - const isNode = typeof require == "function" && !isJSBox; - const isRequest = typeof $request !== "undefined"; - return {isQX, isLoon, isSurge, isNode, isJSBox, isRequest}; -} - -function HTTP(baseURL, defaultOptions = {}) { - const {isQX, isLoon, isSurge} = ENV(); - const methods = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"]; - - function send(method, options) { - options = typeof options === "string" ? {url: options} : options; - options.url = baseURL ? baseURL + options.url : options.url; - options = {...defaultOptions, ...options}; - const timeout = options.timeout; - const events = { - ...{ - onRequest: () => { - }, - onResponse: (resp) => resp, - onTimeout: () => { - }, - }, - ...options.events, - }; - - events.onRequest(method, options); - - let worker; - if (isQX) { - worker = $task.fetch({method, ...options}); - } else { - worker = new Promise((resolve, reject) => { - const request = isSurge || isLoon ? $httpClient : require("request"); - request[method.toLowerCase()](options, (err, response, body) => { - if (err) reject(err); - else - resolve({ - statusCode: response.status || response.statusCode, - headers: response.headers, - body, - }); - }); - }); - } - - let timeoutid; - const timer = timeout - ? new Promise((_, reject) => { - timeoutid = setTimeout(() => { - events.onTimeout(); - return reject( - `${method} URL: ${options.url} exceeds the timeout ${timeout} ms` - ); - }, timeout); - }) - : null; - - return (timer - ? Promise.race([timer, worker]).then((res) => { - clearTimeout(timeoutid); - return res; - }) - : worker - ) - .then((resp) => events.onResponse(resp)) - } - - const http = {}; - methods.forEach( - (method) => - (http[method.toLowerCase()] = (options) => send(method, options)) - ); - return http; -} - -function API(name = "untitled", debug = false) { - const {isQX, isLoon, isSurge, isNode, isJSBox} = ENV(); - return new (class { - constructor(name, debug) { - this.name = name; - this.debug = debug; - - this.http = HTTP(); - this.env = ENV(); - - this.node = (() => { - if (isNode) { - const fs = require("fs"); - - return { - fs, - }; - } else { - return null; - } - })(); - this.initCache(); - - const delay = (t, v) => - new Promise(function (resolve) { - setTimeout(resolve.bind(null, v), t); - }); - - Promise.prototype.delay = function (t) { - return this.then(function (v) { - return delay(t, v); - }); - }; - } - - // persistance - - // initialize cache - initCache() { - if (isQX) this.cache = JSON.parse($prefs.valueForKey(this.name) || "{}"); - if (isLoon || isSurge) - this.cache = JSON.parse($persistentStore.read(this.name) || "{}"); - - if (isNode) { - // create a json for root cache - let fpath = "root.json"; - if (!this.node.fs.existsSync(fpath)) { - this.node.fs.writeFileSync( - fpath, - JSON.stringify({}), - {flag: "wx"}, - (err) => console.log(err) - ); - } - this.root = {}; - - // create a json file with the given name if not exists - fpath = `${this.name}.json`; - if (!this.node.fs.existsSync(fpath)) { - this.node.fs.writeFileSync( - fpath, - JSON.stringify({}), - {flag: "wx"}, - (err) => console.log(err) - ); - this.cache = {}; - } else { - this.cache = JSON.parse( - this.node.fs.readFileSync(`${this.name}.json`) - ); - } - } - } - - // store cache - persistCache() { - const data = JSON.stringify(this.cache); - if (isQX) $prefs.setValueForKey(data, this.name); - if (isLoon || isSurge) $persistentStore.write(data, this.name); - if (isNode) { - this.node.fs.writeFileSync( - `${this.name}.json`, - data, - {flag: "w"}, - (err) => console.log(err) - ); - this.node.fs.writeFileSync( - "root.json", - JSON.stringify(this.root), - {flag: "w"}, - (err) => console.log(err) - ); - } - } - - write(data, key) { - this.log(`SET ${key}`); - if (key.indexOf("#") !== -1) { - key = key.substr(1); - if (isSurge & isLoon) { - $persistentStore.write(data, key); - } - if (isQX) { - $prefs.setValueForKey(data, key); - } - if (isNode) { - this.root[key] = data; - } - } else { - this.cache[key] = data; - } - this.persistCache(); - } - - read(key) { - this.log(`READ ${key}`); - if (key.indexOf("#") !== -1) { - key = key.substr(1); - if (isSurge & isLoon) { - return $persistentStore.read(key); - } - if (isQX) { - return $prefs.valueForKey(key); - } - if (isNode) { - return this.root[key]; - } - } else { - return this.cache[key]; - } - } - - delete(key) { - this.log(`DELETE ${key}`); - if (key.indexOf("#") !== -1) { - key = key.substr(1); - if (isSurge & isLoon) { - $persistentStore.write(null, key); - } - if (isQX) { - $prefs.removeValueForKey(key); - } - if (isNode) { - delete this.root[key]; - } - } else { - delete this.cache[key]; - } - this.persistCache(); - } - - // notification - notify(title, subtitle = "", content = "", options = {}) { - const openURL = options["open-url"]; - const mediaURL = options["media-url"]; - - const content_ = - content + - (openURL ? `\n点击跳转: ${openURL}` : "") + - (mediaURL ? `\n多媒体: ${mediaURL}` : ""); - - if (isQX) $notify(title, subtitle, content, options); - if (isSurge) $notification.post(title, subtitle, content_); - if (isLoon) $notification.post(title, subtitle, content, openURL); - if (isNode) { - if (isJSBox) { - const push = require("push"); - push.schedule({ - title: title, - body: (subtitle ? subtitle + "\n" : "") + content_, - }); - } else { - console.log(`${title}\n${subtitle}\n${content_}\n\n`); - } - } - } - - // other helper functions - log(msg) { - if (this.debug) console.log(msg); - } - - info(msg) { - console.log(msg); - } - - error(msg) { - console.log("ERROR: " + msg); - } - - wait(millisec) { - return new Promise((resolve) => setTimeout(resolve, millisec)); - } - - done(value = {}) { - if (isQX || isLoon || isSurge) { - $done(value); - } else if (isNode && !isJSBox) { - if (typeof $context !== "undefined") { - $context.headers = value.headers; - $context.statusCode = value.statusCode; - $context.body = value.body; - } - } - } - })(name, debug); -} - -/*********************************** Mini Express *************************************/ -function express(port = 3000) { - const {isNode} = ENV(); - - // node support - if (isNode) { - const express_ = require("express"); - const bodyParser = require("body-parser"); - const app = express_(); - app.use(bodyParser.json({verify: rawBodySaver})); - app.use(bodyParser.urlencoded({verify: rawBodySaver, extended: true})); - app.use(bodyParser.raw({verify: rawBodySaver, type: '*/*'})); - - // adapter - app.start = () => { - app.listen(port, () => { - console.log(`Express started on port: ${port}`); - }) - } - return app; - } - - // route handlers - const handlers = []; - - // http methods - const METHODS_NAMES = [ - "GET", - "POST", - "PUT", - "DELETE", - "PATCH", - "OPTIONS", - "HEAD'", - "ALL", - ]; - - // dispatch url to route - const dispatch = (request, start = 0) => { - let {method, url, headers, body} = request; - method = method.toUpperCase(); - const {path, query} = extractURL(url); - let handler = null; - let i; - - for (i = start; i < handlers.length; i++) { - if (handlers[i].method === "ALL" || method === handlers[i].method) { - const {pattern} = handlers[i]; - if (patternMatched(pattern, path)) { - handler = handlers[i]; - break; - } - } - } - if (handler) { - // dispatch to next handler - const next = () => { - dispatch(method, url, i); - }; - const req = { - method, url, path, query, - params: extractPathParams(handler.pattern, path), - headers, body - }; - const res = Response(); - handler.callback(req, res, next).catch(err => { - res.status(500).json({ - status: "failed", - message: err - }); - }); - } else { - // no route, return 404 - const res = Response(); - res.status("404").json({ - status: "failed", - message: "ERROR: 404 not found" - }); - } - }; - - const app = {}; - - // attach http methods - METHODS_NAMES.forEach((method) => { - app[method.toLowerCase()] = (pattern, callback) => { - // add handler - handlers.push({method, pattern, callback}); - }; - }); - - // chainable route - app.route = (pattern) => { - const chainApp = {}; - METHODS_NAMES.forEach((method) => { - chainApp[method.toLowerCase()] = (callback) => { - // add handler - handlers.push({method, pattern, callback}); - return chainApp; - }; - }); - return chainApp; - }; - - // start service - app.start = () => { - dispatch($request); - }; - - return app; - - /************************************************ - Utility Functions - *************************************************/ - function rawBodySaver(req, res, buf, encoding) { - if (buf && buf.length) { - req.rawBody = buf.toString(encoding || 'utf8'); - } - } - - function Response() { - let statusCode = "200"; - const {isQX, isLoon, isSurge} = ENV(); - const headers = { - "Content-Type": "text/plain;charset=UTF-8", - }; - return new (class { - status(code) { - statusCode = code; - return this; - } - - send(body = "") { - const response = { - status: statusCode, - body, - headers, - }; - if (isQX) { - $done(...response); - } else if (isLoon || isSurge) { - $done({ - response, - }); - } - } - - end() { - this.send(); - } - - html(data) { - this.set("Content-Type", "text/html;charset=UTF-8"); - this.send(data); - } - - json(data) { - this.set("Content-Type", "application/json;charset=UTF-8"); - this.send(JSON.stringify(data)); - } - - set(key, val) { - headers[key] = val; - return this; - } - })(); - } - - function patternMatched(pattern, path) { - if (pattern instanceof RegExp && pattern.test(path)) { - return true; - } else { - // root pattern, match all - if (pattern === "/") return true; - // normal string pattern - if (pattern.indexOf(":") === -1) { - const spath = path.split("/"); - const spattern = pattern.split("/"); - for (let i = 0; i < spattern.length; i++) { - if (spath[i] !== spattern[i]) { - return false; - } - } - return true; - } - // string pattern with path parameters - else if (extractPathParams(pattern, path)) { - return true; - } - } - return false; - } - - function extractURL(url) { - // extract path - const match = url.match(/https?:\/\/[^\/]+(\/[^?]*)/) || []; - const path = match[1] || "/"; - - // extract query string - const split = url.indexOf("?"); - const query = {}; - if (split !== -1) { - let hashes = url.slice(url.indexOf("?") + 1).split("&"); - for (let i = 0; i < hashes.length; i++) { - hash = hashes[i].split("="); - query[hash[0]] = hash[1]; - } - } - return { - path, - query, - }; - } - - function extractPathParams(pattern, path) { - if (pattern.indexOf(":") === -1) { - return null; - } else { - const params = {}; - for (let i = 0, j = 0; i < pattern.length; i++, j++) { - if (pattern[i] === ":") { - let key = []; - let val = []; - while (pattern[++i] !== "/" && i < pattern.length) { - key.push(pattern[i]); - } - while (path[j] !== "/" && j < path.length) { - val.push(path[j++]); - } - params[key.join("")] = val.join(""); - } else { - if (pattern[i] !== path[j]) { - return null; - } - } - } - return params; - } - } -} - -/******************************** Base 64 *********************************************/ -// Base64 Coding Library -// https://github.com/dankogai/js-base64#readme -// Under BSD License -function Base64Code() { - // constants - const b64chars - = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - const b64tab = function (bin) { - const t = {}; - let i = 0; - const l = bin.length; - for (; i < l; i++) t[bin.charAt(i)] = i; - return t; - }(b64chars); - const fromCharCode = String.fromCharCode; - // encoder stuff - const cb_utob = function (c) { - let cc; - if (c.length < 2) { - cc = c.charCodeAt(0); - return cc < 0x80 ? c - : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) - + fromCharCode(0x80 | (cc & 0x3f))) - : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | (cc & 0x3f))); - } else { - cc = 0x10000 - + (c.charCodeAt(0) - 0xD800) * 0x400 - + (c.charCodeAt(1) - 0xDC00); - return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) - + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | (cc & 0x3f))); - } - }; - const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; - const utob = function (u) { - return u.replace(re_utob, cb_utob); - }; - const cb_encode = function (ccc) { - const padlen = [0, 2, 1][ccc.length % 3], - ord = ccc.charCodeAt(0) << 16 - | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) - | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), - chars = [ - b64chars.charAt(ord >>> 18), - b64chars.charAt((ord >>> 12) & 63), - padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), - padlen >= 1 ? '=' : b64chars.charAt(ord & 63) - ]; - return chars.join(''); - }; - const btoa = function (b) { - return b.replace(/[\s\S]{1,3}/g, cb_encode); - }; - this.encode = function (u) { - const isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]'; - return isUint8Array ? u.toString('base64') - : btoa(utob(String(u))); - } - const uriencode = function (u, urisafe) { - return !urisafe - ? _encode(u) - : _encode(String(u)).replace(/[+\/]/g, function (m0) { - return m0 === '+' ? '-' : '_'; - }).replace(/=/g, ''); - }; - const encodeURI = function (u) { - return uriencode(u, true) - }; - // decoder stuff - const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; - const cb_btou = function (cccc) { - switch (cccc.length) { - case 4: - const cp = ((0x07 & cccc.charCodeAt(0)) << 18) - | ((0x3f & cccc.charCodeAt(1)) << 12) - | ((0x3f & cccc.charCodeAt(2)) << 6) - | (0x3f & cccc.charCodeAt(3)), - offset = cp - 0x10000; - return (fromCharCode((offset >>> 10) + 0xD800) - + fromCharCode((offset & 0x3FF) + 0xDC00)); - case 3: - return fromCharCode( - ((0x0f & cccc.charCodeAt(0)) << 12) - | ((0x3f & cccc.charCodeAt(1)) << 6) - | (0x3f & cccc.charCodeAt(2)) - ); - default: - return fromCharCode( - ((0x1f & cccc.charCodeAt(0)) << 6) - | (0x3f & cccc.charCodeAt(1)) - ); - } - }; - const btou = function (b) { - return b.replace(re_btou, cb_btou); - }; - const cb_decode = function (cccc) { - const len = cccc.length, - padlen = len % 4, - n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) - | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) - | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) - | (len > 3 ? b64tab[cccc.charAt(3)] : 0), - chars = [ - fromCharCode(n >>> 16), - fromCharCode((n >>> 8) & 0xff), - fromCharCode(n & 0xff) - ]; - chars.length -= [0, 0, 2, 1][padlen]; - return chars.join(''); - }; - const _atob = function (a) { - return a.replace(/\S{1,4}/g, cb_decode); - }; - const atob = function (a) { - return _atob(String(a).replace(/[^A-Za-z0-9\+\/]/g, '')); - }; - const _decode = function (u) { - return btou(_atob(u)) - }; - this.decode = function (a) { - return _decode( - String(a).replace(/[-_]/g, function (m0) { - return m0 === '-' ? '+' : '/' - }) - .replace(/[^A-Za-z0-9\+\/]/g, '') - ).replace(/>/g, ">").replace(/</g, "<"); - }; - this.safeEncode = function (a) { - return this.encode(a.replace(/\+/g, "-").replace(/\//g, "_")); - } - this.safeDecode = function (a) { - return this.decode(a.replace(/-/g, "+").replace(/_/g, "/")); - } -} \ No newline at end of file diff --git a/sub.json b/sub.json deleted file mode 100644 index ab3f9198d0..0000000000 --- a/sub.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "The Name of Subscription", - "url": "The URL of Subscription", - "process": [ - { - "type": "Flag Operator", - "args": [1] - }, - { - "type": "Useless Filter" - }, - { - "type": "Keyword Sort Operator", - "args": ["HK", "TW", "JP"] - }, - { - "type": "Keyword Filter", - "args": ["IEPL", "IPLC"] - }, - { - "type": "Region Filter", - "args": ["HK", "TW", "JP"] - } - ] -} \ No newline at end of file diff --git a/support.nodeseek.com_page_promotion_id=8.png b/support.nodeseek.com_page_promotion_id=8.png new file mode 100644 index 0000000000..52abcc87ae Binary files /dev/null and b/support.nodeseek.com_page_promotion_id=8.png differ diff --git a/vs.code-workspace b/vs.code-workspace new file mode 100644 index 0000000000..876a1499c0 --- /dev/null +++ b/vs.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file