Compare commits

...

4 Commits

Author SHA1 Message Date
xream
f94cf7185a feat: 日志增加 body JSON limit 2025-05-20 21:16:30 +08:00
xream
fa7df51f8c feat: Shadowrocket 支持前置代理. 补充 demo.js 说明
Some checks failed
build / build (push) Has been cancelled
2025-05-18 17:21:54 +08:00
xream
18659d1cc8 feat: Node.js 环境下 API / 路由不自动跳转到 sub-store.vercel.app
Some checks failed
build / build (push) Has been cancelled
2025-05-17 22:49:12 +08:00
xream
1d12dc55bd feat: 单条订阅和文件支持链接参数 produceType raw, 此时返回原始数据的数组 2025-05-17 20:22:24 +08:00
7 changed files with 32 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "sub-store",
"version": "2.19.40",
"version": "2.19.44",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
"main": "src/main.js",
"scripts": {

View File

@@ -11,11 +11,6 @@ export default function Shadowrocket_Producer() {
return false;
} else if (['mieru', 'anytls'].includes(proxy.type)) {
return false;
} else if (proxy['underlying-proxy'] || proxy['dialer-proxy']) {
$.error(
`Shadowrocket 不支持前置代理字段. 已过滤节点 ${proxy.name}. 请使用 App 内的 "代理通过" 功能`,
);
return false;
}
return true;
})

View File

@@ -64,6 +64,7 @@ async function getFile(req, res) {
ignoreFailedRemoteFile,
proxy,
noCache,
produceType,
} = req.query;
let $options = {
_req: {
@@ -128,6 +129,10 @@ async function getFile(req, res) {
if (noCache) {
$.info(`指定不使用缓存: ${noCache}`);
}
if (produceType) {
produceType = decodeURIComponent(produceType);
$.info(`指定生产类型: ${produceType}`);
}
const allFiles = $.read(FILES_KEY);
const file = findByName(allFiles, name);
@@ -144,6 +149,7 @@ async function getFile(req, res) {
$options,
proxy,
noCache,
produceType,
});
try {

View File

@@ -49,11 +49,17 @@ export default function register($app) {
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();
});
if (ENV().isNode) {
$app.get('/', getEnv);
} else {
// 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) {

View File

@@ -173,6 +173,9 @@ async function produceArtifact({
raw.push(sub.content);
}
}
if (produceType === 'raw') {
return (Array.isArray(raw) ? raw : [raw]).flat();
}
// parse proxies
let proxies = (Array.isArray(raw) ? raw : [raw])
.map((i) => ProxyUtils.parse(i))
@@ -570,6 +573,9 @@ async function produceArtifact({
}
}
}
if (produceType === 'raw') {
return (Array.isArray(raw) ? raw : [raw]).flat();
}
const files = (Array.isArray(raw) ? raw : [raw]).flat();
let filesContent = files
.filter((i) => i != null && i !== '')

View File

@@ -17,10 +17,12 @@ export default function express({ substore: $, port, host }) {
const express_ = eval(`require("express")`);
const bodyParser = eval(`require("body-parser")`);
const app = express_();
const limit = eval('process.env.SUB_STORE_BODY_JSON_LIMIT') || '1mb';
$.info(`[BACKEND] body JSON limit: ${limit}`);
app.use(
bodyParser.json({
verify: rawBodySaver,
limit: eval('process.env.SUB_STORE_BODY_JSON_LIMIT') || '1mb',
limit,
}),
);
app.use(
@@ -36,7 +38,7 @@ export default function express({ substore: $, port, host }) {
app.start = () => {
const listener = app.listen(port, host, () => {
const { address, port } = listener.address();
$.info(`[BACKEND] ${address}:${port}`);
$.info(`[BACKEND] listening on ${address}:${port}`);
});
};
return app;

View File

@@ -14,10 +14,12 @@ function operator(proxies = [], targetPlatform, context) {
// 6. `_collectionName` 为组合订阅名, `_collectionDisplayName` 为组合订阅显示名
// 7. `tls-fingerprint` 为 tls 指纹
// 8. `underlying-proxy` 为前置代理, 不同平台会自动转换
// 例如 $server['underlying-proxy'] = '名称'
// 只给 mihomo 输出的话, `dialer-proxy` 也行
// 只给 sing-box 输出的话, `detour` 也行
// 只给 egern 输出的话, `prev_hop` 也行
// 输出到 Clash/Stash/Shadowrocket 时, 会过滤掉配置了前置代理的节点, 并提示使用对应的功能.
// 只给 Egern 输出的话, `prev_hop` 也行
// 只给 Shadowrocket 输出的话, `chain` 也行
// 输出到 Clash/Stash 时, 会过滤掉配置了前置代理的节点, 并提示使用对应的功能.
// 9. `trojan`, `tuic`, `hysteria`, `hysteria2`, `juicity` 会在解析时设置 `tls`: true (会使用 tls 类协议的通用逻辑), 输出时删除
// 10. `sni` 在某些协议里会自动与 `servername` 转换
// 11. 读取节点的 ca-str 和 _ca (后端文件路径) 字段, 自动计算 fingerprint (参考 https://t.me/zhetengsha/1512)