@tool-bridge/server 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{airtable-S3T4TAN7.js → airtable-NOSOMOVB.js} +106 -114
- package/dist/{alt_text_generator_ai-4DIRIDKL.js → alt_text_generator_ai-BHIJ4LW5.js} +25 -16
- package/dist/{amap-LGVGNPML.js → amap-QRLP4TWZ.js} +114 -123
- package/dist/{anthropic-27RFZO35.js → anthropic-IEOI36EV.js} +34 -56
- package/dist/{apify-6WLYAIAS.js → apify-3CCYTQVK.js} +31 -49
- package/dist/{brave_search-K2SVJ66F.js → brave_search-PZNYDQG7.js} +52 -77
- package/dist/chunk-JXHMDBAY.js +45 -0
- package/dist/chunk-LMLX3DJF.js +50 -0
- package/dist/{chunk-YB2FLNWI.js → chunk-RVWZN3CI.js} +2103 -1775
- package/dist/{chunk-BB6ZLMTU.js → chunk-TLNUIPFZ.js} +492 -300
- package/dist/chunk-U5UHT7CX.js +977 -0
- package/dist/chunk-U67V476Y.js +35 -0
- package/dist/chunk-WW2IMPQK.js +283 -0
- package/dist/{chunk-VK3V2WTY.js → chunk-YASUMV2K.js} +4 -6
- package/dist/{circleci-WV3ITU7Q.js → circleci-VSJ4O5FC.js} +36 -55
- package/dist/{clerk-NFQEFKS4.js → clerk-CC2JZBZI.js} +60 -80
- package/dist/{cloudflare_dns-2RK5ASBJ.js → cloudflare_dns-PJEBSEYQ.js} +90 -113
- package/dist/{cohere-5KEW7LWT.js → cohere-KBACYSPF.js} +33 -49
- package/dist/{confluence-SZE63S46.js → confluence-2PX3O7G5.js} +79 -115
- package/dist/{convertapi-QPG2JC5K.js → convertapi-BVOTD2PJ.js} +13 -16
- package/dist/{currencyapi-UO2APQRY.js → currencyapi-6ZQ2VNQ7.js} +30 -53
- package/dist/{deepseek-LJELIMM3.js → deepseek-MB3WVVTB.js} +30 -38
- package/dist/{docker_hub-2MFXSBOF.js → docker_hub-7CLQL2IJ.js} +141 -157
- package/dist/{dropbox-GQYNTTVA.js → dropbox-VFYDVUNK.js} +134 -141
- package/dist/{dub-KI2LHXST.js → dub-QN3EETJY.js} +61 -93
- package/dist/{e2b-WO6ISY3C.js → e2b-NKC3Y776.js} +39 -69
- package/dist/{exa-IZ7B3BPT.js → exa-KKZ6F25K.js} +49 -77
- package/dist/{fal_ai-LTMF36GJ.js → fal_ai-25LYJD2O.js} +37 -44
- package/dist/{feishu-WM7SLSFD.js → feishu-NRT55B3Q.js} +4 -6
- package/dist/{feishu_custom_bot-66W3MXH2.js → feishu_custom_bot-3W3XXUG4.js} +4 -5
- package/dist/{figma-2Z274VQZ.js → figma-4FLP35TC.js} +56 -81
- package/dist/{firehydrant-IFI4R65V.js → firehydrant-BLXPLZ3X.js} +40 -53
- package/dist/{fixer-BCCZEB3D.js → fixer-4OR62TGE.js} +31 -43
- package/dist/{fly-755FXYB5.js → fly-MYCKOZZK.js} +50 -66
- package/dist/{front-4FZKKXXK.js → front-3DFYVMF3.js} +43 -66
- package/dist/{geocodio-WYKDJ3DP.js → geocodio-CXMD6VKA.js} +37 -63
- package/dist/{ghost-5BNQTCOH.js → ghost-4UUE737W.js} +51 -57
- package/dist/{github-ULELF5VX.js → github-WFS2ON2N.js} +48 -41
- package/dist/{gmail-G34WT64J.js → gmail-KW7FXA7A.js} +26 -36
- package/dist/{googlecalendar-BQU255SC.js → googlecalendar-AMH5JQMC.js} +57 -78
- package/dist/{googledocs-HPCNQXYJ.js → googledocs-R5VA6CKD.js} +14 -22
- package/dist/{grafana-VOV24FIC.js → grafana-IT6DWIVB.js} +95 -122
- package/dist/{graphhopper-D5RXW6AP.js → graphhopper-TYFDJZWC.js} +32 -46
- package/dist/index.d.ts +57 -50
- package/dist/index.js +4 -3
- package/dist/{ip2proxy-DAYO7EKZ.js → ip2proxy-GJ4HXVXO.js} +35 -42
- package/dist/{ipgeolocation_io-XD4PSLII.js → ipgeolocation_io-OAGR6PRF.js} +40 -60
- package/dist/{ipqualityscore-K27QEAWK.js → ipqualityscore-BCKAMDGL.js} +30 -42
- package/dist/{jina_ai-E6UXFV2P.js → jina_ai-N3NXRVIZ.js} +32 -58
- package/dist/{jira-ZDSXGQ6W.js → jira-CHLBKWLO.js} +116 -126
- package/dist/{langsmith-TIFJRREW.js → langsmith-OIKOTPY3.js} +101 -121
- package/dist/{lemlist-DASEMJMA.js → lemlist-VAKYPKS3.js} +57 -68
- package/dist/{linear-KE6UP4SP.js → linear-Q6QTPJ5R.js} +109 -118
- package/dist/{logsnag-IMNDN4R5.js → logsnag-SQOQBTES.js} +31 -48
- package/dist/main.js +103 -102
- package/dist/{mattermost-HHHMUXQA.js → mattermost-G2KBEICM.js} +45 -62
- package/dist/{mem0-D2FGGOIY.js → mem0-D2FPLYDX.js} +72 -98
- package/dist/{memos-4OVIGFPH.js → memos-76PTWV5V.js} +68 -122
- package/dist/{metabase-33WCX5YD.js → metabase-TWSIDVBM.js} +47 -60
- package/dist/{mistral_ai-QIMZ2JYL.js → mistral_ai-TP7TQUEJ.js} +35 -40
- package/dist/{mother_duck-M6VWS2VH.js → mother_duck-UXY5THYU.js} +42 -62
- package/dist/{ngrok-Z2PKQBHH.js → ngrok-RZW2ISJK.js} +42 -58
- package/dist/{notes-SS4RPC4K.js → notes-B2I6FWK2.js} +3 -5
- package/dist/{notion-FJCNQ6I7.js → notion-QOKRUE6M.js} +83 -97
- package/dist/{open_exchange_rates-WU57WTT5.js → open_exchange_rates-ODLFWEJ7.js} +35 -39
- package/dist/{openai-JODZ4GKT.js → openai-ZPBPPPGT.js} +51 -55
- package/dist/{opengraph_io-SQRAUSV5.js → opengraph_io-EOI5UJKT.js} +61 -79
- package/dist/{openrouter-Q5XXEJZ7.js → openrouter-BUWLF3BG.js} +41 -55
- package/dist/{outline-RT2EHJ2X.js → outline-NXS3QRXO.js} +89 -104
- package/dist/{paddle-OF2V7GAC.js → paddle-T4MSKQ76.js} +34 -49
- package/dist/{perplexity-LNZEWLHG.js → perplexity-WW5N2LW7.js} +33 -50
- package/dist/{pinecone-JSJIXZYN.js → pinecone-RY5AZPQM.js} +65 -91
- package/dist/{pipedrive-D4CKVUXR.js → pipedrive-OHYQNZTU.js} +37 -59
- package/dist/{polar-M7ZYP6UR.js → polar-XZIAHXS5.js} +43 -53
- package/dist/{posthog-YV7CZOH4.js → posthog-DTPTWORY.js} +58 -77
- package/dist/{postmark-KYHLECRG.js → postmark-F4UCQKC3.js} +52 -71
- package/dist/{prerender-HCMHBKV2.js → prerender-P3Y2MLIC.js} +32 -50
- package/dist/{pubmed-WYVLCCN3.js → pubmed-RHU3GXFB.js} +28 -60
- package/dist/{railway-TWIRD5KR.js → railway-VB6SRLI6.js} +32 -39
- package/dist/{readwise-UZ467IQ7.js → readwise-DIMSKJZR.js} +62 -78
- package/dist/{render-MECUC5CC.js → render-XCCDCEEK.js} +48 -64
- package/dist/{replicate-A5MEK3SW.js → replicate-IUEOQ4JC.js} +41 -58
- package/dist/{resend-BC6EAWJQ.js → resend-N5MJZH5E.js} +27 -37
- package/dist/{rootly-ZM3QDUIS.js → rootly-25T4NBTU.js} +64 -76
- package/dist/{scrapfly-WAML42QJ.js → scrapfly-PK4XFXUA.js} +45 -51
- package/dist/{scrapingbee-DG7PET3V.js → scrapingbee-ITPBMWQU.js} +25 -33
- package/dist/{screenshot_fyi-HY6WTHIO.js → screenshot_fyi-5U6ZYPKR.js} +29 -47
- package/dist/{semantic_scholar-C5IZA7IP.js → semantic_scholar-BJGCI2MU.js} +37 -56
- package/dist/{sentry-OKBPSTDM.js → sentry-63IC263P.js} +66 -85
- package/dist/{shodan-PPC6DYU4.js → shodan-2WBIFHFN.js} +42 -53
- package/dist/{shopify-EWGUHBXO.js → shopify-XLLJRAGM.js} +32 -49
- package/dist/{stripe-6RPDPC5W.js → stripe-WLVCY3UN.js} +4 -5
- package/dist/{supabase-SK7DQ42N.js → supabase-BKNZ35ER.js} +69 -88
- package/dist/{tavily-YCG5VQMH.js → tavily-YFSDEUTL.js} +37 -62
- package/dist/{telegram-2OES5FYB.js → telegram-FC35W74G.js} +168 -177
- package/dist/{telnyx-POOSBBR4.js → telnyx-MI32XZUG.js} +30 -50
- package/dist/{todoist-M7YD6YSS.js → todoist-4ZFJKZC6.js} +77 -89
- package/dist/{trello-IS6V5W3E.js → trello-UOGFNMK4.js} +108 -122
- package/dist/{turso-RCFHUFVH.js → turso-YTSTW3ZS.js} +52 -64
- package/dist/{twilio-OS2RXFGO.js → twilio-XAJDFUQH.js} +48 -55
- package/dist/{umami-PQ2SJ2LN.js → umami-ZVIUBPAI.js} +49 -69
- package/dist/{unsplash-C6BPZO4E.js → unsplash-IU3PLDNS.js} +35 -52
- package/dist/{upstash_redis-WH6UER7H.js → upstash_redis-3EYJW7SY.js} +28 -40
- package/dist/{uptimerobot-M3YZGS6Z.js → uptimerobot-PJG2ASRU.js} +11 -12
- package/dist/{v2ex-R4JWTEHN.js → v2ex-KFQWWGFC.js} +36 -61
- package/dist/{vercel-FZVYUOQD.js → vercel-I2ZDOQRL.js} +124 -150
- package/dist/{webapi-VLM4IKVB.js → webapi-GW5QXWXE.js} +1 -1
- package/dist/{wolfram_alpha_api-2KOLO5DC.js → wolfram_alpha_api-BNXOJMB6.js} +26 -34
- package/dist/{wordpress-XRWGO6LG.js → wordpress-36D7BSMP.js} +87 -104
- package/dist/{workos-WR4NKOYL.js → workos-6X4JJRRC.js} +37 -56
- package/dist/{zhihu-BKZIB3WA.js → zhihu-CIXKCHIU.js} +35 -57
- package/package.json +5 -5
- package/dist/chunk-2O27H4Y2.js +0 -183
- package/dist/chunk-GKX72JMJ.js +0 -378
- package/dist/chunk-MLKGABMK.js +0 -9
|
@@ -1,83 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProviderHttpClient
|
|
3
|
+
} from "./chunk-WW2IMPQK.js";
|
|
4
|
+
import {
|
|
5
|
+
asJsonObject,
|
|
6
|
+
trimmedText
|
|
7
|
+
} from "./chunk-JXHMDBAY.js";
|
|
1
8
|
import {
|
|
2
9
|
createProviderPlugin,
|
|
3
10
|
requireApiKey,
|
|
4
11
|
upstreamError
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import
|
|
7
|
-
guardedFetch
|
|
8
|
-
} from "./chunk-2O27H4Y2.js";
|
|
9
|
-
import "./chunk-GKX72JMJ.js";
|
|
12
|
+
} from "./chunk-YASUMV2K.js";
|
|
13
|
+
import "./chunk-U5UHT7CX.js";
|
|
10
14
|
import {
|
|
11
15
|
TBError,
|
|
12
16
|
external_exports
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-RVWZN3CI.js";
|
|
18
|
+
import "./chunk-U67V476Y.js";
|
|
15
19
|
|
|
16
20
|
// ../plugins/src/zhihu/api.ts
|
|
17
21
|
var SERVICE = "zhihu";
|
|
18
22
|
var API_BASE = "https://developer.zhihu.com";
|
|
23
|
+
var http = createProviderHttpClient({ baseUrl: `${API_BASE}/`, service: SERVICE });
|
|
19
24
|
var CODE_STATUS = {
|
|
20
25
|
10001: 400,
|
|
21
26
|
20001: 401,
|
|
22
27
|
30001: 429
|
|
23
28
|
};
|
|
24
|
-
function asRecord(value) {
|
|
25
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
26
|
-
}
|
|
27
|
-
function optionalText(value) {
|
|
28
|
-
if (typeof value !== "string") return void 0;
|
|
29
|
-
const trimmed = value.trim();
|
|
30
|
-
return trimmed === "" ? void 0 : trimmed;
|
|
31
|
-
}
|
|
32
29
|
function errorMessage(payload) {
|
|
33
|
-
const direct =
|
|
30
|
+
const direct = trimmedText(payload);
|
|
34
31
|
if (direct !== void 0) return direct;
|
|
35
|
-
const record =
|
|
32
|
+
const record = asJsonObject(payload);
|
|
36
33
|
if (record === void 0) return void 0;
|
|
37
|
-
const nested =
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
async function readPayload(response) {
|
|
41
|
-
const text = await response.text();
|
|
42
|
-
if (text === "") return {};
|
|
43
|
-
try {
|
|
44
|
-
return JSON.parse(text);
|
|
45
|
-
} catch {
|
|
46
|
-
throw upstreamError(502, "\u77E5\u4E4E\u8FD4\u56DE\u4E86\u975E\u6CD5 JSON");
|
|
47
|
-
}
|
|
34
|
+
const nested = asJsonObject(record.error);
|
|
35
|
+
return trimmedText(record.Message) ?? trimmedText(record.msg) ?? trimmedText(record.message) ?? trimmedText(nested?.message);
|
|
48
36
|
}
|
|
49
37
|
async function request(ctx, input) {
|
|
50
38
|
const apiKey = requireApiKey(ctx, SERVICE);
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
...input.body === void 0 ? {} : { body: JSON.stringify(input.body) }
|
|
66
|
-
});
|
|
67
|
-
} catch (error) {
|
|
68
|
-
throw upstreamError(
|
|
39
|
+
const response = await http.request({
|
|
40
|
+
method: input.method ?? "GET",
|
|
41
|
+
path: input.path,
|
|
42
|
+
query: Object.entries(input.query ?? {}).map(([key, value]) => [key, value === void 0 ? void 0 : String(value)]),
|
|
43
|
+
headers: {
|
|
44
|
+
"authorization": `Bearer ${apiKey}`,
|
|
45
|
+
// 上游对 GET 也发这个头。无 body 时它没有意义,但照搬以免改变打给上游的请求形状。
|
|
46
|
+
"content-type": "application/json",
|
|
47
|
+
"x-request-timestamp": String(Math.floor(Date.now() / 1e3))
|
|
48
|
+
},
|
|
49
|
+
...input.body === void 0 ? {} : { json: input.body },
|
|
50
|
+
invalidJsonMessage: "\u77E5\u4E4E\u8FD4\u56DE\u4E86\u975E\u6CD5 JSON",
|
|
51
|
+
mapError: ({ bodyKind, data, status }) => bodyKind === "invalid-json" ? upstreamError(502, "\u77E5\u4E4E\u8FD4\u56DE\u4E86\u975E\u6CD5 JSON") : upstreamError(status, errorMessage(data) ?? `\u77E5\u4E4E\u8BF7\u6C42\u5931\u8D25(HTTP ${status})`),
|
|
52
|
+
mapTransportError: ({ message }) => upstreamError(
|
|
69
53
|
502,
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
const payload =
|
|
74
|
-
|
|
75
|
-
throw upstreamError(
|
|
76
|
-
response.status,
|
|
77
|
-
errorMessage(payload) ?? `\u77E5\u4E4E\u8BF7\u6C42\u5931\u8D25(HTTP ${response.status})`
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
const code = asRecord(payload)?.Code;
|
|
54
|
+
message === void 0 ? "\u77E5\u4E4E\u8BF7\u6C42\u5931\u8D25" : `\u77E5\u4E4E\u8BF7\u6C42\u5931\u8D25: ${message}`
|
|
55
|
+
)
|
|
56
|
+
});
|
|
57
|
+
const payload = response.bodyKind === "empty" ? {} : response.data;
|
|
58
|
+
const code = asJsonObject(payload)?.Code;
|
|
81
59
|
if (typeof code === "number" && Number.isFinite(code) && code !== 0) {
|
|
82
60
|
throw upstreamError(
|
|
83
61
|
CODE_STATUS[code] ?? 502,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tool-bridge/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "tool-bridge self-hosted server: run the HTBP gateway on Node with SQLite or PostgreSQL persistence, filesystem object storage and WebSocket device channel — single container via docker run",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"ioredis": "^6.0.0",
|
|
41
41
|
"postgres": "^3.4.9",
|
|
42
42
|
"ws": "8.21.0",
|
|
43
|
-
"@tool-bridge/dashboard": "0.
|
|
43
|
+
"@tool-bridge/dashboard": "0.23.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"tsup": "^8.5.1",
|
|
50
50
|
"tsx": "^4.23.0",
|
|
51
51
|
"vitest": "^4.1.10",
|
|
52
|
-
"@tool-bridge/app": "0.
|
|
53
|
-
"@tool-bridge/
|
|
54
|
-
"@tool-bridge/
|
|
52
|
+
"@tool-bridge/app": "0.16.0",
|
|
53
|
+
"@tool-bridge/plugins": "0.1.0",
|
|
54
|
+
"@tool-bridge/core": "0.1.0"
|
|
55
55
|
},
|
|
56
56
|
"repository": {
|
|
57
57
|
"type": "git",
|
package/dist/chunk-2O27H4Y2.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TBError
|
|
3
|
-
} from "./chunk-YB2FLNWI.js";
|
|
4
|
-
|
|
5
|
-
// ../plugins/src/_runtime/ipPolicy.ts
|
|
6
|
-
function parseIpv4(value) {
|
|
7
|
-
const parts = value.split(".");
|
|
8
|
-
if (parts.length !== 4) return void 0;
|
|
9
|
-
let result = 0;
|
|
10
|
-
for (const part of parts) {
|
|
11
|
-
if (!/^\d{1,3}$/.test(part) || part.length > 1 && part.startsWith("0")) return void 0;
|
|
12
|
-
const octet = Number(part);
|
|
13
|
-
if (octet > 255) return void 0;
|
|
14
|
-
result = result << 8 | octet;
|
|
15
|
-
}
|
|
16
|
-
return result >>> 0;
|
|
17
|
-
}
|
|
18
|
-
function parseIpv6(value) {
|
|
19
|
-
let text = value;
|
|
20
|
-
if (text.startsWith("[") && text.endsWith("]")) text = text.slice(1, -1);
|
|
21
|
-
const zone = text.indexOf("%");
|
|
22
|
-
if (zone !== -1) text = text.slice(0, zone);
|
|
23
|
-
if (!text.includes(":")) return void 0;
|
|
24
|
-
const halves = text.split("::");
|
|
25
|
-
if (halves.length > 2) return void 0;
|
|
26
|
-
const expand = (part) => {
|
|
27
|
-
if (part === "") return [];
|
|
28
|
-
const groups2 = [];
|
|
29
|
-
const chunks = part.split(":");
|
|
30
|
-
for (let i = 0; i < chunks.length; i += 1) {
|
|
31
|
-
const chunk = chunks[i];
|
|
32
|
-
if (i === chunks.length - 1 && chunk.includes(".")) {
|
|
33
|
-
const v4 = parseIpv4(chunk);
|
|
34
|
-
if (v4 === void 0) return void 0;
|
|
35
|
-
groups2.push(v4 >>> 16 & 65535, v4 & 65535);
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (!/^[0-9a-fA-F]{1,4}$/.test(chunk)) return void 0;
|
|
39
|
-
groups2.push(Number.parseInt(chunk, 16));
|
|
40
|
-
}
|
|
41
|
-
return groups2;
|
|
42
|
-
};
|
|
43
|
-
const head = expand(halves[0] ?? "");
|
|
44
|
-
const tail = halves.length === 2 ? expand(halves[1] ?? "") : [];
|
|
45
|
-
if (head === void 0 || tail === void 0) return void 0;
|
|
46
|
-
const missing = 8 - head.length - tail.length;
|
|
47
|
-
if (halves.length === 2 ? missing < 0 : missing !== 0) return void 0;
|
|
48
|
-
const groups = [...head, ...Array.from({ length: halves.length === 2 ? missing : 0 }, () => 0), ...tail];
|
|
49
|
-
if (groups.length !== 8) return void 0;
|
|
50
|
-
const bytes = new Uint8Array(16);
|
|
51
|
-
groups.forEach((group, i) => {
|
|
52
|
-
bytes[i * 2] = group >>> 8 & 255;
|
|
53
|
-
bytes[i * 2 + 1] = group & 255;
|
|
54
|
-
});
|
|
55
|
-
return bytes;
|
|
56
|
-
}
|
|
57
|
-
function classifyIpv4(value) {
|
|
58
|
-
const a = value >>> 24 & 255;
|
|
59
|
-
const b = value >>> 16 & 255;
|
|
60
|
-
const c = value >>> 8 & 255;
|
|
61
|
-
if (a === 0) return "blocked";
|
|
62
|
-
if (a === 10) return "blocked";
|
|
63
|
-
if (a === 127) return "blocked";
|
|
64
|
-
if (a === 169 && b === 254) return "blocked";
|
|
65
|
-
if (a === 172 && b >= 16 && b <= 31) return "blocked";
|
|
66
|
-
if (a === 192 && b === 0 && c === 0) return "blocked";
|
|
67
|
-
if (a === 192 && b === 0 && c === 2) return "blocked";
|
|
68
|
-
if (a === 192 && b === 168) return "blocked";
|
|
69
|
-
if (a === 198 && (b === 18 || b === 19)) return "blocked";
|
|
70
|
-
if (a === 198 && b === 51 && c === 100) return "blocked";
|
|
71
|
-
if (a === 203 && b === 0 && c === 113) return "blocked";
|
|
72
|
-
if (a === 100 && b >= 64 && b <= 127) return "blocked";
|
|
73
|
-
if (a >= 224) return "blocked";
|
|
74
|
-
return "public";
|
|
75
|
-
}
|
|
76
|
-
function classifyIpv6(bytes) {
|
|
77
|
-
const isZero = bytes.every((byte) => byte === 0);
|
|
78
|
-
if (isZero) return "blocked";
|
|
79
|
-
if (bytes.slice(0, 15).every((byte) => byte === 0) && bytes[15] === 1) return "blocked";
|
|
80
|
-
const v4Mapped = bytes.slice(0, 10).every((byte) => byte === 0) && (bytes[10] === 255 && bytes[11] === 255 || bytes[10] === 0 && bytes[11] === 0);
|
|
81
|
-
if (v4Mapped) {
|
|
82
|
-
const v4 = (bytes[12] << 24 | bytes[13] << 16 | bytes[14] << 8 | bytes[15]) >>> 0;
|
|
83
|
-
return classifyIpv4(v4);
|
|
84
|
-
}
|
|
85
|
-
const first = bytes[0];
|
|
86
|
-
if ((first & 254) === 252) return "blocked";
|
|
87
|
-
if (first === 254 && (bytes[1] & 192) === 128) return "blocked";
|
|
88
|
-
if (first === 255) return "blocked";
|
|
89
|
-
if (first === 32 && bytes[1] === 1 && bytes[2] === 13 && bytes[3] === 184) return "blocked";
|
|
90
|
-
return "public";
|
|
91
|
-
}
|
|
92
|
-
function isIpAddress(value) {
|
|
93
|
-
return parseIpv4(value) !== void 0 || parseIpv6(value) !== void 0;
|
|
94
|
-
}
|
|
95
|
-
function classifyIpAddress(address) {
|
|
96
|
-
const v4 = parseIpv4(address);
|
|
97
|
-
if (v4 !== void 0) return classifyIpv4(v4);
|
|
98
|
-
const v6 = parseIpv6(address);
|
|
99
|
-
if (v6 !== void 0) return classifyIpv6(v6);
|
|
100
|
-
return "blocked";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ../plugins/src/_runtime/guardedFetch.ts
|
|
104
|
-
var MAX_REDIRECTS = 5;
|
|
105
|
-
var CROSS_ORIGIN_STRIPPED_HEADERS = [
|
|
106
|
-
"authorization",
|
|
107
|
-
"cookie",
|
|
108
|
-
"proxy-authorization"
|
|
109
|
-
// 各家自定义的密钥头没有统一命名,凡是名字里带 key/token/secret 的一律剥掉:
|
|
110
|
-
// 宁可让跨源跳转少带一个无关头,也不能漏带走一个凭证。
|
|
111
|
-
];
|
|
112
|
-
function looksLikeCredentialHeader(name) {
|
|
113
|
-
return /(?:^|-)(?:api[-_]?key|key|token|secret|auth)(?:$|-)/i.test(name);
|
|
114
|
-
}
|
|
115
|
-
function stripCredentials(headers, sensitiveHeaders) {
|
|
116
|
-
const next = new Headers(headers);
|
|
117
|
-
for (const [name] of headers) {
|
|
118
|
-
if (CROSS_ORIGIN_STRIPPED_HEADERS.includes(name.toLowerCase()) || looksLikeCredentialHeader(name) || sensitiveHeaders.has(name.toLowerCase())) {
|
|
119
|
-
next.delete(name);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return next;
|
|
123
|
-
}
|
|
124
|
-
var EgressBlockedError = class extends TBError {
|
|
125
|
-
constructor(message) {
|
|
126
|
-
super("invalid_argument", message);
|
|
127
|
-
this.name = "EgressBlockedError";
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
function assertPublicHttpUrl(value) {
|
|
131
|
-
let url;
|
|
132
|
-
try {
|
|
133
|
-
url = value instanceof URL ? value : new URL(value);
|
|
134
|
-
} catch {
|
|
135
|
-
throw new EgressBlockedError(`\u51FA\u7AD9\u76EE\u6807\u4E0D\u662F\u5408\u6CD5 URL: ${String(value)}`);
|
|
136
|
-
}
|
|
137
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
138
|
-
throw new EgressBlockedError(`\u51FA\u7AD9\u76EE\u6807\u534F\u8BAE\u4E0D\u88AB\u5141\u8BB8: ${url.protocol}`);
|
|
139
|
-
}
|
|
140
|
-
const hostname = url.hostname.startsWith("[") && url.hostname.endsWith("]") ? url.hostname.slice(1, -1) : url.hostname;
|
|
141
|
-
if (hostname === "") throw new EgressBlockedError("\u51FA\u7AD9\u76EE\u6807\u7F3A\u5C11\u4E3B\u673A\u540D");
|
|
142
|
-
if (isIpAddress(hostname) && classifyIpAddress(hostname) === "blocked") {
|
|
143
|
-
throw new EgressBlockedError("\u51FA\u7AD9\u76EE\u6807\u6307\u5411\u79C1\u6709\u6216\u4FDD\u7559\u5730\u5740");
|
|
144
|
-
}
|
|
145
|
-
return url;
|
|
146
|
-
}
|
|
147
|
-
function createGuardedFetch(options = {}) {
|
|
148
|
-
const crossOriginRedirect = options.crossOriginRedirect ?? "follow";
|
|
149
|
-
const maxRedirects = options.maxRedirects ?? MAX_REDIRECTS;
|
|
150
|
-
const sensitiveHeaders = new Set(
|
|
151
|
-
(options.sensitiveHeaders ?? []).map((name) => name.toLowerCase())
|
|
152
|
-
);
|
|
153
|
-
return async function guardedFetch2(input, init) {
|
|
154
|
-
const transport = options.fetch ?? globalThis.fetch;
|
|
155
|
-
const initial = input instanceof Request ? input.url : String(input);
|
|
156
|
-
let url = assertPublicHttpUrl(initial);
|
|
157
|
-
let request = input instanceof Request ? new Request(url, new Request(input, init)) : new Request(url, { ...init, redirect: "manual" });
|
|
158
|
-
for (let hop = 0; ; hop += 1) {
|
|
159
|
-
const response = await transport(new Request(request, { redirect: "manual" }));
|
|
160
|
-
const location = response.headers.get("location");
|
|
161
|
-
if (response.status < 300 || response.status > 399 || location === null) return response;
|
|
162
|
-
if (hop >= maxRedirects) {
|
|
163
|
-
throw new EgressBlockedError(`\u51FA\u7AD9\u91CD\u5B9A\u5411\u8D85\u8FC7 ${maxRedirects} \u8DF3`);
|
|
164
|
-
}
|
|
165
|
-
const previousOrigin = new URL(request.url).origin;
|
|
166
|
-
url = assertPublicHttpUrl(new URL(location, url));
|
|
167
|
-
const crossesOrigin = url.origin !== previousOrigin;
|
|
168
|
-
if (crossesOrigin && crossOriginRedirect === "error") {
|
|
169
|
-
throw new EgressBlockedError("\u643A\u5E26\u654F\u611F\u4FE1\u606F\u7684\u51FA\u7AD9\u8BF7\u6C42\u4E0D\u5141\u8BB8\u8DE8\u6E90\u91CD\u5B9A\u5411");
|
|
170
|
-
}
|
|
171
|
-
const headers = !crossesOrigin ? request.headers : stripCredentials(request.headers, sensitiveHeaders);
|
|
172
|
-
const downgrade = response.status === 303 || (response.status === 301 || response.status === 302) && request.method !== "GET";
|
|
173
|
-
request = downgrade ? new Request(url, { method: "GET", headers, redirect: "manual" }) : new Request(url, { ...request, headers, redirect: "manual" });
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
var guardedFetch = createGuardedFetch();
|
|
178
|
-
|
|
179
|
-
export {
|
|
180
|
-
assertPublicHttpUrl,
|
|
181
|
-
createGuardedFetch,
|
|
182
|
-
guardedFetch
|
|
183
|
-
};
|