+
+ 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 91a5e97c9..abf5c0803 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,69 @@
-# Sub-Store
-> This project is still under active development. Current version: v0.1 (backend only).
+
+
+
+
+
+
Sub-Store
+
+
+
+Advanced Subscription Manager for QX, Loon, Surge, Stash, Egern and Shadowrocket.
+
+
+[](https://github.com/sub-store-org/Sub-Store/actions/workflows/main.yml)     
+
+[](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(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)
+- [x] Stash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, TUIC, Juicity, SSH)
+- [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] Clash
+- [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
## 2. Subscription Formatting
+
### Filtering
-- [x] **Keyword filter**
-- [x] **Discard keywords filter**
+
- [x] **Regex filter**
- [x] **Discard regex filter**
- [x] **Region filter**
@@ -32,13 +72,53 @@ 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.
+
+[](https://app.fossa.com/projects/git%2Bgithub.com%2FPeng-YM%2FSub-Store?ref=badge_large)
+
+## Star History
+
+[](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.
diff --git a/backend/.babelrc b/backend/.babelrc
new file mode 100644
index 000000000..d45171f44
--- /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 000000000..919fea0ca
--- /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 000000000..984872170
--- /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 000000000..635659231
--- /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 000000000..05d6bd66c
--- /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 000000000..e1961530e
--- /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 000000000..dd44c5748
--- /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 000000000..e69de29bb
diff --git a/backend/gulpfile.babel.js b/backend/gulpfile.babel.js
new file mode 100644
index 000000000..d865f71c9
--- /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 000000000..df83de409
--- /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 c5780687e..bbcf42409 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,11 +1,68 @@
{
- "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.16.52",
+ "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",
+ "dependencies": {
+ "@maxmind/geoip2-node": "^5.0.0",
+ "automerge": "1.0.1-preview.7",
+ "body-parser": "^1.19.0",
+ "buffer": "^6.0.3",
+ "connect-history-api-fallback": "^2.0.0",
+ "cron": "^3.1.6",
+ "dns-packet": "^5.6.1",
+ "express": "^4.17.1",
+ "http-proxy-middleware": "^2.0.6",
+ "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",
+ "request": "^2.88.2",
+ "semver": "^7.6.3",
+ "static-js-yaml": "^1.0.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/pnpm-lock.yaml b/backend/pnpm-lock.yaml
new file mode 100644
index 000000000..8a82513c9
--- /dev/null
+++ b/backend/pnpm-lock.yaml
@@ -0,0 +1,9435 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+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: ^2.0.6
+ version: 2.0.7
+ 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
+ request:
+ specifier: ^2.88.2
+ version: 2.88.2
+ semver:
+ specifier: ^7.6.3
+ version: 7.6.3
+ static-js-yaml:
+ specifier: ^1.0.0
+ version: 1.0.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==}
+
+ asn1@0.2.6:
+ resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
+
+ 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'}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ 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'}
+
+ aws-sign2@0.7.0:
+ resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
+
+ aws4@1.13.2:
+ resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==}
+
+ 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'}
+
+ bcrypt-pbkdf@1.0.2:
+ resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
+
+ 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==}
+
+ caseless@0.12.0:
+ resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
+
+ 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==}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ 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==}
+
+ dashdash@1.14.1:
+ resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
+ engines: {node: '>=0.10'}
+
+ 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==}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ 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==}
+
+ ecc-jsbn@0.1.2:
+ resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
+
+ 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'}
+
+ forever-agent@0.6.1:
+ resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
+
+ fork-stream@0.0.4:
+ resolution: {integrity: sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==}
+
+ form-data@2.3.3:
+ resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
+ engines: {node: '>= 0.12'}
+
+ 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'}
+
+ getpass@0.1.7:
+ resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
+
+ 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'}
+
+ har-schema@2.0.0:
+ resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
+ engines: {node: '>=4'}
+
+ har-validator@5.1.5:
+ resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
+ engines: {node: '>=6'}
+ deprecated: this library is no longer supported
+
+ 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@2.0.7:
+ resolution: {integrity: sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ '@types/express': ^4.17.13
+ peerDependenciesMeta:
+ '@types/express':
+ optional: true
+
+ http-proxy@1.18.1:
+ resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
+ engines: {node: '>=8.0.0'}
+
+ http-signature@1.2.0:
+ resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==}
+ engines: {node: '>=0.8', npm: '>=1.3.7'}
+
+ 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-obj@3.0.0:
+ resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==}
+ engines: {node: '>=10'}
+
+ 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-typedarray@1.0.0:
+ resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+
+ 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'}
+
+ isstream@0.1.2:
+ resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
+
+ 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@0.1.1:
+ resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
+
+ 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==}
+
+ json-stringify-safe@5.0.1:
+ resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+
+ 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@1.4.2:
+ resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
+ engines: {node: '>=0.6.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'}
+
+ oauth-sign@0.9.0:
+ resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
+
+ 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
+
+ performance-now@2.1.0:
+ resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+
+ 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'}
+
+ psl@1.15.0:
+ resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
+
+ 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'}
+
+ qs@6.5.3:
+ resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
+ 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'}
+
+ request@2.88.2:
+ resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
+ engines: {node: '>= 6'}
+ deprecated: request has been deprecated, see https://github.com/request/request/issues/3142
+
+ 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==}
+
+ sshpk@1.18.0:
+ resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==}
+ engines: {node: '>=0.10.0'}
+ hasBin: true
+
+ 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
+
+ tough-cookie@2.5.0:
+ resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
+ engines: {node: '>=0.8'}
+
+ transform-ast@2.4.4:
+ resolution: {integrity: sha512-AxjeZAcIOUO2lev2GDe3/xZ1Q0cVGjIMk5IsriTy8zbWlsEnjeB025AhkhBJHoy997mXpLd4R+kRbvnnQVuQHQ==}
+
+ tty-browserify@0.0.1:
+ resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==}
+
+ tunnel-agent@0.6.0:
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+
+ tweetnacl@0.14.5:
+ resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
+
+ 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==}
+
+ 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
+
+ asn1@0.2.6:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ 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
+
+ asynckit@0.4.0: {}
+
+ 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
+
+ aws-sign2@0.7.0: {}
+
+ aws4@1.13.2: {}
+
+ axios@0.21.4:
+ dependencies:
+ follow-redirects: 1.15.9
+ 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
+
+ bcrypt-pbkdf@1.0.2:
+ dependencies:
+ tweetnacl: 0.14.5
+
+ 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: {}
+
+ caseless@0.12.0: {}
+
+ 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
+
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
+ 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: {}
+
+ dashdash@1.14.1:
+ dependencies:
+ assert-plus: 1.0.0
+
+ 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: {}
+
+ delayed-stream@1.0.0: {}
+
+ 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
+
+ ecc-jsbn@0.1.2:
+ dependencies:
+ jsbn: 0.1.1
+ safer-buffer: 2.1.2
+
+ 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: {}
+
+ 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
+
+ forever-agent@0.6.1: {}
+
+ fork-stream@0.0.4: {}
+
+ form-data@2.3.3:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+
+ 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: {}
+
+ getpass@0.1.7:
+ dependencies:
+ assert-plus: 1.0.0
+
+ 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
+
+ har-schema@2.0.0: {}
+
+ har-validator@5.1.5:
+ dependencies:
+ ajv: 6.12.6
+ har-schema: 2.0.0
+
+ 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@2.0.7:
+ dependencies:
+ '@types/http-proxy': 1.17.15
+ http-proxy: 1.18.1
+ is-glob: 4.0.3
+ is-plain-obj: 3.0.0
+ micromatch: 4.0.8
+ transitivePeerDependencies:
+ - debug
+
+ http-proxy@1.18.1:
+ dependencies:
+ eventemitter3: 4.0.7
+ follow-redirects: 1.15.9
+ requires-port: 1.0.0
+ transitivePeerDependencies:
+ - debug
+
+ http-signature@1.2.0:
+ dependencies:
+ assert-plus: 1.0.0
+ jsprim: 1.4.2
+ sshpk: 1.18.0
+
+ 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-obj@3.0.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-typedarray@1.0.0: {}
+
+ 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: {}
+
+ isstream@0.1.2: {}
+
+ 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@0.1.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: {}
+
+ json-stringify-safe@5.0.1: {}
+
+ json5@2.2.3: {}
+
+ jsonparse@1.3.1: {}
+
+ jsprim@1.4.2:
+ dependencies:
+ assert-plus: 1.0.0
+ extsprintf: 1.3.0
+ json-schema: 0.4.0
+ verror: 1.10.0
+
+ 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: {}
+
+ oauth-sign@0.9.0: {}
+
+ 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
+
+ performance-now@2.1.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
+
+ psl@1.15.0:
+ dependencies:
+ punycode: 2.3.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
+
+ qs@6.5.3: {}
+
+ 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
+
+ request@2.88.2:
+ dependencies:
+ aws-sign2: 0.7.0
+ aws4: 1.13.2
+ caseless: 0.12.0
+ combined-stream: 1.0.8
+ extend: 3.0.2
+ forever-agent: 0.6.1
+ form-data: 2.3.3
+ har-validator: 5.1.5
+ http-signature: 1.2.0
+ is-typedarray: 1.0.0
+ isstream: 0.1.2
+ json-stringify-safe: 5.0.1
+ mime-types: 2.1.35
+ oauth-sign: 0.9.0
+ performance-now: 2.1.0
+ qs: 6.5.3
+ safe-buffer: 5.2.1
+ tough-cookie: 2.5.0
+ tunnel-agent: 0.6.0
+ uuid: 3.4.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: {}
+
+ sshpk@1.18.0:
+ dependencies:
+ asn1: 0.2.6
+ assert-plus: 1.0.0
+ bcrypt-pbkdf: 1.0.2
+ dashdash: 1.14.1
+ ecc-jsbn: 0.1.2
+ getpass: 0.1.7
+ jsbn: 0.1.1
+ safer-buffer: 2.1.2
+ tweetnacl: 0.14.5
+
+ 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: {}
+
+ tough-cookie@2.5.0:
+ dependencies:
+ psl: 1.15.0
+ punycode: 2.3.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: {}
+
+ tunnel-agent@0.6.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ tweetnacl@0.14.5: {}
+
+ 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: {}
+
+ 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 000000000..d832a2567
--- /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 000000000..08517b604
--- /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 000000000..5ad0993d5
--- /dev/null
+++ b/backend/src/core/proxy-utils/index.js
@@ -0,0 +1,623 @@
+import { Buffer } from 'buffer';
+import rs from '@/utils/rs';
+import YAML from '@/utils/yaml';
+import download 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';
+
+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 noCache;
+ let url = content || '';
+ if (url.endsWith('#noCache')) {
+ url = url.replace(/#noCache$/, '');
+ noCache = true;
+ }
+ // 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]}${noCache ? '#noCache' : ''}`;
+ 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;
+ }
+ }
+
+ 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,
+ isValidUUID,
+};
+
+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 (['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 (
+ ['shadowsocks'].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 000000000..14b44a5e4
--- /dev/null
+++ b/backend/src/core/proxy-utils/parsers/index.js
@@ -0,0 +1,1576 @@
+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];
+
+ const proxy = {
+ name: decodeURIComponent(line.split('#')[1]),
+ 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;
+ }
+ 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);
+ 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 && params.sni && params.sni !== '') {
+ proxy.sni = params.sni;
+ }
+ 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;
+
+ 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 (['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_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;
+ }
+
+ 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;
+
+ 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 {
+ 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(),
+ 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 000000000..961503740
--- /dev/null
+++ b/backend/src/core/proxy-utils/parsers/peggy/loon.js
@@ -0,0 +1,204 @@
+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/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/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/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/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/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/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/others)* {
+ proxy.type = "http";
+ proxy.tls = true;
+}
+http = tag equals "http"i address (username password)? (fast_open/udp_relay/ip_mode/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/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'); }
+
+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'; }
+
+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 000000000..60f3623e2
--- /dev/null
+++ b/backend/src/core/proxy-utils/parsers/peggy/loon.peg
@@ -0,0 +1,194 @@
+// 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/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/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/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/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/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/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/others)* {
+ proxy.type = "http";
+ proxy.tls = true;
+}
+http = tag equals "http"i address (username password)? (fast_open/udp_relay/ip_mode/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/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'); }
+
+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'; }
+
+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 000000000..197e9c926
--- /dev/null
+++ b/backend/src/core/proxy-utils/parsers/peggy/qx.js
@@ -0,0 +1,204 @@
+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/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");
+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"); }
+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 000000000..809311f81
--- /dev/null
+++ b/backend/src/core/proxy-utils/parsers/peggy/qx.peg
@@ -0,0 +1,194 @@
+// 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/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");
+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"); }
+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 000000000..6599cf00a
--- /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(""); }
+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 000000000..e82ecbbd8
--- /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(""); }
+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 000000000..bc27623d3
--- /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 000000000..c97d8e9e7
--- /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 000000000..2c866038f
--- /dev/null
+++ b/backend/src/core/proxy-utils/preprocessors/index.js
@@ -0,0 +1,164 @@
+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:([ ]*[^,\n}]*)/g,
+ (matched, value) => {
+ const afterTrim = value.trim();
+
+ // 为空
+ if (!afterTrim || afterTrim === '') {
+ return 'short-id: ""';
+ }
+
+ // 是否被引号包裹
+ if (/^(['"]).*\1$/.test(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 000000000..5cc4a403a
--- /dev/null
+++ b/backend/src/core/proxy-utils/processors/index.js
@@ -0,0 +1,1143 @@
+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,
+} 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(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 ((!oA && !oB) || (oA && oB && oA === oB))
+ return a.name < b.name ? -1 : 1; // fallback to normal sort
+ });
+ },
+ };
+}
+
+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);
+ // if (typeof patch !== 'object') patch = {};
+ if (typeof patch !== 'object')
+ throw new Error('patch is not an object');
+ output.$content = ProxyUtils.yaml.safeDump(
+ deepMerge(
+ {
+ 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') {
+ const config = {
+ proxies: await produceArtifact({
+ type: $file.sourceType || 'collection',
+ name: $file.sourceName,
+ platform: 'mihomo',
+ produceType: 'internal',
+ produceOpts: {
+ 'delete-underscore-fields': true
+ }
+ }),
+ }
+ $content = ProxyUtils.yaml.safeDump(await main(config))
+ }
+ } 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(regions) {
+ 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);
+ return regions.some((r) => REGION_MAP[r] === flag);
+ });
+ },
+ };
+}
+
+// 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(types) {
+ return {
+ name: 'Type Filter',
+ func: (proxies) => {
+ return proxies.map((proxy) => types.some((t) => proxy.type === t));
+ },
+ };
+}
+
+/**
+ 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,
+ };
+ 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 000000000..8f4268d8d
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/clash.js
@@ -0,0 +1,193 @@
+import { isPresent } from '@/core/proxy-utils/producers/utils';
+
+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;
+ }
+ 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 (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) => ' - ' + 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 000000000..a4ce88991
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/clashmeta.js
@@ -0,0 +1,215 @@
+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;
+ }
+ 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 000000000..91631acd3
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/egern.js
@@ -0,0 +1,400 @@
+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 (proxy.plugin === 'obfs') {
+ proxy.obfs = proxy['plugin-opts'].mode;
+ proxy.obfs_host = proxy['plugin-opts'].host;
+ proxy.obfs_uri = proxy['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 (proxy['obfs-password'] && proxy.obfs == 'salamander') {
+ proxy.obfs = 'salamander';
+ proxy.obfs_password = proxy['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 000000000..2915a7757
--- /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 000000000..363a36cad
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/loon.js
@@ -0,0 +1,592 @@
+/* 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);
+ case 'vless':
+ return vless(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');
+
+ // 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, includeUnsupportedProxy) {
+ 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');
+
+ // 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');
+
+ // 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 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',
+ );
+
+ // 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');
+
+ // 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) {
+ if (typeof proxy.flow !== 'undefined' || proxy['reality-opts']) {
+ throw new Error(`VLESS XTLS/REALITY 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',
+ );
+
+ // 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');
+
+ // 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');
+ 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');
+
+ // 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');
+
+ 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');
+
+ // 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 000000000..eae9ea5db
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/qx.js
@@ -0,0 +1,584 @@
+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);
+ 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) {
+ 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',
+ ].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');
+
+ // 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 000000000..2fab6a075
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/shadowrocket.js
@@ -0,0 +1,231 @@
+import { isPresent } from '@/core/proxy-utils/producers/utils';
+
+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;
+ }
+ 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 000000000..3c6a9d898
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/sing-box.js
@@ -0,0 +1,848 @@
+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;
+};
+
+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 = true;
+ 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 = {}, includeUnsupportedProxy) => {
+ 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 (includeUnsupportedProxy) {
+ 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 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;
+ 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 000000000..a947590df
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/stash.js
@@ -0,0 +1,307 @@
+import { isPresent } from '@/core/proxy-utils/producers/utils';
+
+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',
+ ...(opts['include-unsupported-proxy']
+ ? [
+ '2022-blake3-aes-128-gcm',
+ '2022-blake3-aes-256-gcm',
+ ]
+ : []),
+ ].includes(proxy.cipher)) ||
+ (proxy.type === 'snell' && String(proxy.version) === '4') ||
+ (proxy.type === 'vless' && proxy['reality-opts'])
+ ) {
+ 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 (proxy['underlying-proxy']) {
+ proxy['dialer-proxy'] = proxy['underlying-proxy'];
+ }
+ delete proxy['underlying-proxy'];
+
+ 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 000000000..02c5ad111
--- /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 000000000..01c89e870
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/surge.js
@@ -0,0 +1,1131 @@
+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) {
+ 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 000000000..40c14874e
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/surgemac.js
@@ -0,0 +1,183 @@
+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,
+ nameserver: [
+ 'https://223.6.6.6/dns-query',
+ 'https://120.53.53.53/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 000000000..caf8ec39a
--- /dev/null
+++ b/backend/src/core/proxy-utils/producers/uri.js
@@ -0,0 +1,592 @@
+/* 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 || /^_/i.test(key)) {
+ delete proxy[key];
+ }
+ }
+ if (
+ ['trojan', 'tuic', 'hysteria', 'hysteria2', 'juicity'].includes(
+ proxy.type,
+ )
+ ) {
+ delete proxy.tls;
+ }
+ if (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['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]) {
+ 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',
+ ].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 (proxy[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 '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]) {
+ 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 000000000..e8dc964d0
--- /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 000000000..bdb3c68d5
--- /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 000000000..e69de29bb
diff --git a/backend/src/core/rule-utils/index.js b/backend/src/core/rule-utils/index.js
new file mode 100644
index 000000000..0152d71ed
--- /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 000000000..755665243
--- /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 000000000..8e78d128f
--- /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 000000000..d11577ffe
--- /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 000000000..03737d8d7
--- /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';
+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 000000000..004440ea9
--- /dev/null
+++ b/backend/src/products/cron-sync-artifacts.js
@@ -0,0 +1,241 @@
+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 = [];
+ allArtifacts.map((artifact) => {
+ if (artifact.sync && artifact.source) {
+ 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 (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 000000000..d373f1e45
--- /dev/null
+++ b/backend/src/products/resource-parser.loon.js
@@ -0,0 +1,93 @@
+/* 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}
+ ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅
+ `,
+ );
+
+ let arg;
+ if (typeof $argument != 'undefined') {
+ arg = Object.fromEntries(
+ $argument.split('&').map((item) => item.split('=')),
+ );
+ } else {
+ arg = {};
+ }
+
+ const RESOURCE_TYPE = {
+ PROXY: 1,
+ RULE: 2,
+ };
+
+ result = resource;
+
+ if (resourceType === RESOURCE_TYPE.PROXY) {
+ try {
+ let proxies = ProxyUtils.parse(resource);
+ result = ProxyUtils.produce(proxies, 'Loon', undefined, {
+ 'include-unsupported-proxy': arg?.includeUnsupportedProxy,
+ });
+ } 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,
+ });
+ } catch (e) {
+ console.log(e.message ?? e);
+ }
+ }
+ } else if (resourceType === RESOURCE_TYPE.RULE) {
+ 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 000000000..04bc160a9
--- /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 000000000..1a17b8ec8
--- /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 000000000..e4626a382
--- /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 000000000..cdf29cb6d
--- /dev/null
+++ b/backend/src/restful/collections.js
@@ -0,0 +1,152 @@
+import { deleteByName, findByName, updateByName } from '@/utils/database';
+import { COLLECTIONS_KEY, ARTIFACTS_KEY } from '@/constants';
+import { failed, success } from '@/restful/response';
+import $ from '@/core/app';
+import { RequestInvalidError, ResourceNotFoundError } from '@/restful/errors';
+
+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}_${new Date()
+ .toLocaleString('zh-CN', {
+ year: 'numeric',
+ day: 'numeric',
+ month: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ })
+ .replace(/\D/g, '')}.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;
+ }
+ }
+ $.write(allArtifacts, ARTIFACTS_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 000000000..6f1cfa39a
--- /dev/null
+++ b/backend/src/restful/download.js
@@ -0,0 +1,756 @@
+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 } 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 = {};
+ 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', 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',
+ [subUserInfo, flowInfo]
+ .filter((i) => i)
+ .join('; ')
+ .replace(/\s*;\s*;\s*/g, ';'),
+ );
+ }
+
+ 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 = {};
+ 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',
+ subUserInfo.replace(/\s*;\s*;\s*/g, ';'),
+ );
+ }
+ 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 000000000..a1946b4e2
--- /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 000000000..51ee72e59
--- /dev/null
+++ b/backend/src/restful/file.js
@@ -0,0 +1,296 @@
+import { deleteByName, findByName, updateByName } from '@/utils/database';
+import { getFlowHeaders } from '@/utils/flow';
+import { FILES_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';
+
+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);
+
+ $.info(`正在下载文件:${name}`);
+ let {
+ url,
+ subInfoUrl,
+ subInfoUserAgent,
+ ua,
+ content,
+ mergeSources,
+ ignoreFailedRemoteFile,
+ proxy,
+ noCache,
+ } = req.query;
+ let $options = {};
+ 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',
+ flowInfo.replace(/\s*;\s*;\s*/g, ';'),
+ );
+ }
+ }
+ } 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}_${new Date()
+ .toLocaleString('zh-CN', {
+ year: 'numeric',
+ day: 'numeric',
+ month: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ })
+ .replace(/\D/g, '')}.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}...`);
+
+ 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 000000000..f1dee5aac
--- /dev/null
+++ b/backend/src/restful/index.js
@@ -0,0 +1,276 @@
+import express from '@/vendor/express';
+import $ from '@/core/app';
+import migrate from '@/utils/migration';
+import download from '@/utils/download';
+import { syncArtifacts } 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 });
+ // 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
+ );
+ }
+ 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 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'),
+ );
+ if (fe_path) {
+ 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_share_rewrite = '/share/:type/:name';
+ let be_api_rewrite = '';
+ let be_download_rewrite = '';
+ let be_api = '/api/';
+ let be_download = '/download/';
+ 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}`,
+ changeOrigin: true,
+ pathRewrite: (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 path;
+ },
+ }),
+ );
+ app.use(
+ be_api_rewrite,
+ createProxyMiddleware({
+ target: `http://127.0.0.1:${port}`,
+ pathRewrite: (path) => {
+ const newPath = path.startsWith(be_api_rewrite)
+ ? path.replace(be_api_rewrite, be_api)
+ : path;
+ return newPath.includes('?')
+ ? `${newPath}&share=true`
+ : `${newPath}?share=true`;
+ },
+ }),
+ );
+ app.use(
+ be_download_rewrite,
+ createProxyMiddleware({
+ target: `http://127.0.0.1:${port}`,
+ changeOrigin: true,
+ pathRewrite: (path) => {
+ return path.startsWith(be_download_rewrite)
+ ? path.replace(be_download_rewrite, be_download)
+ : path;
+ },
+ }),
+ );
+ }
+
+ 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} -> http://127.0.0.1:${port}${be_api}`,
+ );
+ $.info(
+ `[FRONTEND -> BACKEND] ${fe_address}:${fe_port}${be_download_rewrite} -> http://127.0.0.1:${port}${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 000000000..ea650a59a
--- /dev/null
+++ b/backend/src/restful/miscs.js
@@ -0,0 +1,191 @@
+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';
+
+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_${new Date()
+ .toLocaleString('zh-CN', {
+ year: 'numeric',
+ day: 'numeric',
+ month: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ })
+ .replace(/\D/g, '')}.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':
+ // 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 000000000..6ef888554
--- /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 000000000..17ddc7744
--- /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 000000000..d5b1888b1
--- /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 000000000..7d5c8613e
--- /dev/null
+++ b/backend/src/restful/preview.js
@@ -0,0 +1,328 @@
+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);
+ } catch (err) {
+ errors[url] = err;
+ $.error(
+ `文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`,
+ );
+ return '';
+ }
+ }),
+ );
+
+ if (
+ !file.ignoreFailedRemoteFile &&
+ Object.keys(errors).length > 0
+ ) {
+ throw new Error(
+ `文件 ${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 (!sub.ignoreFailedRemoteSub && Object.keys(errors).length > 0) {
+ throw new Error(
+ `订阅 ${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 (
+ !sub.ignoreFailedRemoteSub &&
+ Object.keys(errors).length > 0
+ ) {
+ throw new Error(
+ `订阅 ${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 (
+ !collection.ignoreFailedRemoteSub &&
+ Object.keys(errors).length > 0
+ ) {
+ throw new Error(
+ `组合订阅 ${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 000000000..4ded89135
--- /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 000000000..c880e433e
--- /dev/null
+++ b/backend/src/restful/settings.js
@@ -0,0 +1,146 @@
+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`);
+ settings.artifactStoreStatus = 'NOT FOUND';
+ }
+ } catch (err) {
+ $.error(`查找 Sub-Store Gist 时发生错误: ${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 000000000..03240e05f
--- /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 000000000..d8425f6e0
--- /dev/null
+++ b/backend/src/restful/subscriptions.js
@@ -0,0 +1,376 @@
+import {
+ NetworkError,
+ InternalServerError,
+ ResourceNotFoundError,
+ RequestInvalidError,
+} from './errors';
+import { deleteByName, findByName, updateByName } from '@/utils/database';
+import { SUBS_KEY, COLLECTIONS_KEY, ARTIFACTS_KEY } from '@/constants';
+import {
+ getFlowHeaders,
+ parseFlowHeaders,
+ getRmainingDays,
+} from '@/utils/flow';
+import { success, failed } from './response';
+import $ from '@/core/app';
+
+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}_${new Date()
+ .toLocaleString('zh-CN', {
+ year: 'numeric',
+ day: 'numeric',
+ month: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ })
+ .replace(/\D/g, '')}.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;
+ }
+ }
+
+ $.write(allCols, COLLECTIONS_KEY);
+ $.write(allArtifacts, ARTIFACTS_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 000000000..6117a7220
--- /dev/null
+++ b/backend/src/restful/sync.js
@@ -0,0 +1,838 @@
+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 (type === 'subscription') {
+ 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 (!subIgnoreFailedRemoteSub && Object.keys(errors).length > 0) {
+ throw new Error(
+ `订阅 ${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 (!subIgnoreFailedRemoteSub && Object.keys(errors).length > 0) {
+ throw new Error(
+ `订阅 ${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 (type === 'collection') {
+ 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 (
+ !sub.ignoreFailedRemoteSub &&
+ Object.keys(errors).length > 0
+ ) {
+ throw new Error(
+ `订阅 ${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 (
+ !collectionIgnoreFailedRemoteSub &&
+ Object.keys(errors).length > 0
+ ) {
+ throw new Error(
+ `组合订阅 ${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 = '';
+ console.log(file);
+ 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 (
+ !fileIgnoreFailedRemoteFile &&
+ Object.keys(errors).length > 0
+ ) {
+ throw new Error(
+ `文件 ${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 = [];
+ allArtifacts.map((artifact) => {
+ if (artifact.sync && artifact.source) {
+ 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 (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 000000000..deb3f83ec
--- /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 000000000..37c1ca822
--- /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 000000000..a6662fa3d
--- /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 000000000..24819d33d
--- /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 000000000..863922951
--- /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 000000000..9786046b1
--- /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 000000000..0c7366d5a
--- /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 000000000..dadae3f0c
--- /dev/null
+++ b/backend/src/utils/download.js
@@ -0,0 +1,275 @@
+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;
+}
diff --git a/backend/src/utils/env.js b/backend/src/utils/env.js
new file mode 100644
index 000000000..d7249bd69
--- /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 000000000..111118506
--- /dev/null
+++ b/backend/src/utils/flow.js
@@ -0,0 +1,315 @@
+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}`);
+ }
+}
diff --git a/backend/src/utils/geo.js b/backend/src/utils/geo.js
new file mode 100644
index 000000000..c4b36e105
--- /dev/null
+++ b/backend/src/utils/geo.js
@@ -0,0 +1,504 @@
+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'],
+ '🇧🇷': ['BR', 'BRA'],
+ '🇧🇾': ['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'],
+ '🇭🇰': ['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'],
+ '🇱🇹': ['LT', 'LTU'],
+ '🇱🇺': ['LU', 'LUX'],
+ '🇱🇻': ['LV', 'LVA'],
+ '🇲🇦': ['MA', 'MAR'],
+ '🇲🇩': ['MD', 'MDA'],
+ '🇳🇬': ['NG', 'NGA'],
+ '🇲🇰': ['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'],
+ '🇷🇴': ['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', '巴西', '圣保罗'],
+ '🇧🇾': ['Belarus', '白俄罗斯', '白俄'],
+ '🇧🇴': ['Bolivia', '玻利维亚'],
+ '🇨🇦': [
+ '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', '希腊', '希臘'],
+ '🇬🇹': ['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'],
+ '🇱🇹': ['Lithuania', '立陶宛'],
+ '🇱🇺': ['Luxembourg', '卢森堡'],
+ '🇱🇻': ['Latvia', '拉脱维亚', 'Latvija'],
+ '🇲🇦': ['Morocco', '摩洛哥'],
+ '🇲🇩': ['Moldova', '摩尔多瓦', '摩爾多瓦'],
+ '🇳🇬': ['Nigeria', '尼日利亚', '尼日利亞'],
+ '🇲🇰': ['Macedonia', '马其顿', '馬其頓'],
+ '🇲🇳': ['Mongolia', '蒙古'],
+ '🇲🇴': ['Macao', '澳门', '澳門', 'CTM'],
+ '🇲🇹': ['Malta', '马耳他'],
+ '🇲🇽': ['Mexico', '墨西哥'],
+ '🇲🇾': ['Malaysia', '马来', '馬來', '吉隆坡', '大馬'],
+ '🇳🇱': [
+ 'Netherlands',
+ '荷兰',
+ '荷蘭',
+ '尼德蘭',
+ '阿姆斯特丹',
+ 'Amsterdam',
+ ],
+ '🇳🇴': ['Norway', '挪威'],
+ '🇳🇵': ['Nepal', '尼泊尔'],
+ '🇳🇿': ['New Zealand', '新西兰', '新西蘭'],
+ '🇵🇦': ['Panama', '巴拿马'],
+ '🇵🇪': ['Peru', '秘鲁', '祕魯'],
+ '🇵🇭': ['Philippines', '菲律宾', '菲律賓'],
+ '🇵🇰': ['Pakistan', '巴基斯坦'],
+ '🇵🇱': ['Poland', '波兰', '波蘭', '华沙', 'Warsaw'],
+ '🇵🇷': ['Puerto Rico', '波多黎各'],
+ '🇵🇹': ['Portugal', '葡萄牙'],
+ '🇵🇾': ['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 000000000..a6736d713
--- /dev/null
+++ b/backend/src/utils/gist.js
@@ -0,0 +1,285 @@
+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);
+ 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');
+ }
+ }
+}
diff --git a/backend/src/utils/headers-resource-cache.js b/backend/src/utils/headers-resource-cache.js
new file mode 100644
index 000000000..a4bf92ed6
--- /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 000000000..daf6e769f
--- /dev/null
+++ b/backend/src/utils/index.js
@@ -0,0 +1,143 @@
+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,
+ )
+ );
+}
+
+export {
+ 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 000000000..c58cc5771
--- /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 000000000..80a8a956f
--- /dev/null
+++ b/backend/src/utils/migration.js
@@ -0,0 +1,128 @@
+import {
+ SUBS_KEY,
+ COLLECTIONS_KEY,
+ SCHEMA_VERSION_KEY,
+ ARTIFACTS_KEY,
+ RULES_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. 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 000000000..34db7bf98
--- /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 000000000..bf9c46562
--- /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 000000000..e9f2d91c4
--- /dev/null
+++ b/backend/src/utils/script-resource-cache.js
@@ -0,0 +1,115 @@
+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() {
+ // 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), SCRIPT_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(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 000000000..a1e10c522
--- /dev/null
+++ b/backend/src/utils/user-agent.js
@@ -0,0 +1,91 @@
+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) {
+ 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'].includes(target)) {
+ return false;
+ }
+ const version = coerce(ua).version;
+ if (
+ platform === 'Stash' &&
+ target === 'Stash' &&
+ gte(version, '2.8.0')
+ ) {
+ return true;
+ }
+ if (
+ platform === 'Egern' &&
+ target === 'Egern' &&
+ gte(version, '1.29.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 000000000..9ea9c0e00
--- /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 000000000..a2c7220ee
--- /dev/null
+++ b/backend/src/vendor/express.js
@@ -0,0 +1,296 @@
+/* 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: '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 000000000..9bbcd0817
--- /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 000000000..4d8129823
--- /dev/null
+++ b/backend/src/vendor/open-api.js
@@ -0,0 +1,438 @@
+/* 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();
+
+ 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((resolve, reject) => {
+ const request = isNode
+ ? eval("require('request')")
+ : $httpClient;
+ const body = options.body;
+ const opts = JSON.parse(JSON.stringify(options));
+ opts.body = body;
+
+ if (!isNode && opts.timeout) {
+ opts.timeout++;
+ 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}`);
+ }
+ request[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 cbd9691b9..000000000
--- 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 2c32851c7..000000000
--- 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 000000000..83a99b5fe
--- /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 000000000..7ccf8d718
--- /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 000000000..07377cfae
--- /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 000000000..2a1f9a114
--- /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 000000000..6fd46218f
--- /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 000000000..91fb19967
--- /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 000000000..6e18828e2
--- /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 000000000..024263777
--- /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 000000000..3eb98f172
--- /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 000000000..82a17d676
--- /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 000000000..7f37b5356
--- /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 000000000..db4b9822a
--- /dev/null
+++ b/scripts/demo.js
@@ -0,0 +1,268 @@
+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` 为前置代理
+ // 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`
+
+ // 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
+
+ // 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(id, data)
+ // cache.get(id)
+
+ // 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
+ // 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 000000000..8181e5bfb
--- /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 000000000..650ded1c0
--- /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 000000000..bda8c792f
--- /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 000000000..e69de29bb
diff --git a/scripts/revert.js b/scripts/revert.js
new file mode 100644
index 000000000..c64cc1b71
--- /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 000000000..20838a9bc
--- /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 000000000..7bd76af07
--- /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 000000000..58c45c559
--- /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 403adbc1e..000000000
--- 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 4f753635d..000000000
--- 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 e9558405f..000000000
--- 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 67a0bd8a5..000000000
--- 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 d7e10b5c8..000000000
--- 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 df36fcfb7..000000000
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 412352865..000000000
--- a/sub-store-web/public/index.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
- <%= htmlWebpackPlugin.options.title %>
-
-
-
- We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.
-
-
-
-
-
diff --git a/sub-store-web/src/App.vue b/sub-store-web/src/App.vue
deleted file mode 100644
index 55df31532..000000000
--- 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 f3d2503fc..000000000
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 879051a29..000000000
--- a/sub-store-web/src/components/HelloWorld.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
{{ msg }}
-
- For a guide and recipes on how to configure / customize this project,
- check out the
- vue-cli documentation .
-
-
Installed CLI Plugins
-
-
Essential Links
-
-
Ecosystem
-
-
-
-
-
-
-
-
diff --git a/sub-store-web/src/main.js b/sub-store-web/src/main.js
deleted file mode 100644
index 01433bca2..000000000
--- 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 cbd9691b9..000000000
--- 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 ab3f9198d..000000000
--- 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/vs.code-workspace b/vs.code-workspace
new file mode 100644
index 000000000..876a1499c
--- /dev/null
+++ b/vs.code-workspace
@@ -0,0 +1,8 @@
+{
+ "folders": [
+ {
+ "path": "."
+ }
+ ],
+ "settings": {}
+}
\ No newline at end of file
diff --git "a/\346\234\200\346\226\260\345\220\214\346\255\245" "b/\346\234\200\346\226\260\345\220\214\346\255\245"
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ "b/\346\234\200\346\226\260\345\220\214\346\255\245"
@@ -0,0 +1 @@
+