Compare commits

...

10 Commits

10 changed files with 1561 additions and 1136 deletions

View File

@@ -45,18 +45,14 @@ jobs:
cd backend
SUBSTORE_RELEASE=`node --eval="process.stdout.write(require('./package.json').version)"`
echo "release_tag=$SUBSTORE_RELEASE" >> $GITHUB_OUTPUT
- name: Prepare release
run: |
cd backend
pnpm i -D conventional-changelog-cli
pnpm run changelog
- name: Release
uses: softprops/action-gh-release@v1
if: ${{ success() }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
body_path: ./backend/CHANGELOG.md
tag_name: ${{ steps.tag.outputs.release_tag }}
generate_release_notes: true
files: |
./backend/sub-store.min.js
./backend/dist/sub-store-0.min.js

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const { build } = require('esbuild');
let content = fs.readFileSync(path.join(__dirname, 'sub-store.min.js'), {
encoding: 'utf8',
@@ -14,10 +14,12 @@ fs.writeFileSync(path.join(__dirname, 'dist/sub-store.no-bundle.js'), content, {
encoding: 'utf8',
});
const { build } = require('estrella');
build({
entry: 'dist/sub-store.no-bundle.js',
outfile: 'dist/sub-store.bundle.js',
entryPoints: ['dist/sub-store.no-bundle.js'],
bundle: true,
minify: true,
sourcemap: true,
platform: 'node',
format: 'cjs',
outfile: 'dist/sub-store.bundle.js',
});

View File

@@ -1,6 +1,6 @@
{
"name": "sub-store",
"version": "2.14.116",
"version": "2.14.125",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js",
"scripts": {
@@ -9,15 +9,16 @@
"serve": "node sub-store.min.js",
"start": "nodemon -w src -w package.json --exec babel-node src/main.js",
"build": "gulp",
"bundle": "node bundle.js",
"changelog": "conventional-changelog -p cli -i CHANGELOG.md -s"
"bundle": "node bundle.js"
},
"author": "Peng-YM",
"license": "GPL-3.0",
"dependencies": {
"automerge": "1.0.1-preview.7",
"body-parser": "^1.19.0",
"connect-history-api-fallback": "^2.0.0",
"express": "^4.17.1",
"http-proxy-middleware": "^2.0.6",
"js-base64": "^3.7.2",
"lodash": "^4.17.21",
"request": "^2.88.2",
@@ -38,6 +39,7 @@
"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",

2496
backend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -605,6 +605,22 @@ function ScriptFilter(script, targetPlatform, $arguments, source) {
})();
return output;
},
nodeFunc: async (proxies) => {
let output = FULL(proxies.length, true);
await (async function () {
const filter = createDynamicFunction(
'filter',
`async function filter(proxies = []) {
return proxies.filter(($server = {}) => {
${script}
})
}`,
$arguments,
);
output = filter(proxies, targetPlatform, { source, ...env });
})();
return output;
},
};
}
@@ -635,7 +651,29 @@ async function ApplyFilter(filter, objs) {
} catch (err) {
// print log and skip this filter
$.error(`Cannot apply filter ${filter.name}\n Reason: ${err}`);
throw new Error(`脚本过滤失败 ${err.message ?? err}`);
let funcErr = '';
let funcErrMsg = `${err.message ?? err}`;
if (funcErrMsg.includes('$server is not defined')) {
funcErr = '';
} else {
funcErr = `执行 function filter 失败 ${funcErrMsg}; `;
}
try {
selected = await filter.nodeFunc(objs);
} catch (err) {
$.error(
`Cannot apply filter ${filter.name}(node script)! Reason: ${err}`,
);
let nodeErr = '';
let nodeErrMsg = `${err.message ?? err}`;
if (funcErr && nodeErrMsg === funcErrMsg) {
nodeErr = '';
funcErr = `执行失败 ${funcErrMsg}`;
} else {
nodeErr = `执行节点快捷过滤脚本 失败 ${nodeErr}`;
}
throw new Error(`脚本过滤 ${funcErr}${nodeErr}`);
}
}
return objs.filter((_, i) => selected[i]);
}

View File

@@ -99,7 +99,7 @@ function trojan(proxy) {
if (proxy.network === 'ws') {
result.append(`,transport=ws`);
result.appendIfPresent(
`,path=${proxy['ws-opts'].path}`,
`,path=${proxy['ws-opts']?.path}`,
'ws-opts.path',
);
result.appendIfPresent(

View File

@@ -258,11 +258,11 @@ export default function URI_Producer() {
if (proxy.tfo) {
hysteria2params.push(`fastopen=1`);
}
result = `hysteria2://${proxy.password}@${proxy.server}:${
proxy.port
}?${hysteria2params.join('&')}#${encodeURIComponent(
proxy.name,
)}`;
result = `hysteria2://${encodeURIComponent(proxy.password)}@${
proxy.server
}:${proxy.port}?${hysteria2params.join(
'&',
)}#${encodeURIComponent(proxy.name)}`;
break;
}
return result;

View File

@@ -18,8 +18,8 @@ export default function serve() {
let port;
let host;
if ($.env.isNode) {
port = eval('process.env.SUB_STORE_BACKEND_API_PORT');
host = eval('process.env.SUB_STORE_BACKEND_API_HOST');
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
@@ -37,4 +37,79 @@ export default function serve() {
registerMiscRoutes($app);
$app.start();
if ($.env.isNode) {
const path = eval(`require("path")`);
const fs = eval(`require("fs")`);
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) {
throw new 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_rewrite = '';
let be_api = '/api/';
if (fe_be_path) {
if (!fe_be_path.startsWith('/')) {
throw new Error(
'SUB_STORE_FRONTEND_BACKEND_PATH should start with /',
);
}
be_rewrite = `${fe_be_path === '/' ? '' : fe_be_path}${be_api}`;
app.use(
be_rewrite,
createProxyMiddleware({
target: `http://127.0.0.1:${port}`,
changeOrigin: true,
pathRewrite: (path) => {
return path.startsWith(be_rewrite)
? path.replace(be_rewrite, be_api)
: 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_rewrite} -> http://127.0.0.1:${port}${be_api}`,
);
}
});
}
}
}

View File

@@ -2,8 +2,6 @@
import { ENV } from './open-api';
export default function express({ substore: $, port, host }) {
port = port || 3000;
host = host || '::';
const { isNode } = ENV();
const DEFAULT_HEADERS = {
'Content-Type': 'text/plain;charset=UTF-8',
@@ -32,7 +30,7 @@ export default function express({ substore: $, port, host }) {
app.start = () => {
const listener = app.listen(port, host, () => {
const { address, port } = listener.address();
$.info(`Express started on ${address}:${port}`);
$.info(`[BACKEND] ${address}:${port}`);
});
};
return app;

40
package-lock.json generated
View File

@@ -1,40 +0,0 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"requires": {
"follow-redirects": "1.5.10"
}
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
}