@tool-bridge/server 0.16.0 → 0.19.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-23JBIM6X.js} +106 -114
- package/dist/{alt_text_generator_ai-4DIRIDKL.js → alt_text_generator_ai-ADWBTCIH.js} +25 -16
- package/dist/{amap-LGVGNPML.js → amap-CYQCYW2Z.js} +114 -123
- package/dist/{anthropic-27RFZO35.js → anthropic-5P62HDNR.js} +34 -56
- package/dist/{apify-6WLYAIAS.js → apify-54RZUAGW.js} +31 -49
- package/dist/{brave_search-K2SVJ66F.js → brave_search-AHJ6FTD5.js} +52 -77
- package/dist/{chunk-VK3V2WTY.js → chunk-B4P6YZFS.js} +4 -6
- package/dist/{chunk-BB6ZLMTU.js → chunk-CLEZ6YQ6.js} +2600 -481
- package/dist/chunk-JXHMDBAY.js +45 -0
- package/dist/chunk-LMLX3DJF.js +50 -0
- package/dist/{chunk-YB2FLNWI.js → chunk-OKRZPQ3R.js} +2558 -1926
- package/dist/chunk-SWBNHIO4.js +977 -0
- package/dist/chunk-U67V476Y.js +35 -0
- package/dist/chunk-VLOIDU5U.js +283 -0
- package/dist/{circleci-WV3ITU7Q.js → circleci-UM3NSQJ3.js} +36 -55
- package/dist/{clerk-NFQEFKS4.js → clerk-FE5LQ2CZ.js} +60 -80
- package/dist/{cloudflare_dns-2RK5ASBJ.js → cloudflare_dns-KEZABKUT.js} +90 -113
- package/dist/{cohere-5KEW7LWT.js → cohere-4IPJADXP.js} +33 -49
- package/dist/{confluence-SZE63S46.js → confluence-56QEKNQI.js} +79 -115
- package/dist/{convertapi-QPG2JC5K.js → convertapi-3QRM5K5T.js} +13 -16
- package/dist/{currencyapi-UO2APQRY.js → currencyapi-L6G4OND5.js} +30 -53
- package/dist/{deepseek-LJELIMM3.js → deepseek-LGC6HBFG.js} +30 -38
- package/dist/{docker_hub-2MFXSBOF.js → docker_hub-XDMK3BIU.js} +141 -157
- package/dist/{dropbox-GQYNTTVA.js → dropbox-4QARMFZU.js} +134 -141
- package/dist/{dub-KI2LHXST.js → dub-C6JSJKOT.js} +61 -93
- package/dist/{e2b-WO6ISY3C.js → e2b-6A6TVACJ.js} +39 -69
- package/dist/{exa-IZ7B3BPT.js → exa-SIWWW6AA.js} +49 -77
- package/dist/{fal_ai-LTMF36GJ.js → fal_ai-3IJXOKSP.js} +37 -44
- package/dist/{feishu-WM7SLSFD.js → feishu-L4KDA4DC.js} +4 -6
- package/dist/{feishu_custom_bot-66W3MXH2.js → feishu_custom_bot-SDM75H4P.js} +4 -5
- package/dist/{figma-2Z274VQZ.js → figma-6DD436DN.js} +56 -81
- package/dist/{firehydrant-IFI4R65V.js → firehydrant-SYSGYB3R.js} +40 -53
- package/dist/{fixer-BCCZEB3D.js → fixer-FZG7ASTF.js} +31 -43
- package/dist/{fly-755FXYB5.js → fly-HMRCZBUC.js} +50 -66
- package/dist/{front-4FZKKXXK.js → front-FAFSD7I3.js} +43 -66
- package/dist/{geocodio-WYKDJ3DP.js → geocodio-4D3TWENM.js} +37 -63
- package/dist/{ghost-5BNQTCOH.js → ghost-OSO2FOZS.js} +51 -57
- package/dist/{github-ULELF5VX.js → github-OR4I4RHE.js} +48 -41
- package/dist/{gmail-G34WT64J.js → gmail-5AOPJ63E.js} +26 -36
- package/dist/{googlecalendar-BQU255SC.js → googlecalendar-SOJIJUWH.js} +57 -78
- package/dist/{googledocs-HPCNQXYJ.js → googledocs-QSKN5TLN.js} +14 -22
- package/dist/{grafana-VOV24FIC.js → grafana-R3AIZM7M.js} +95 -122
- package/dist/{graphhopper-D5RXW6AP.js → graphhopper-4CR3QOAX.js} +32 -46
- package/dist/index.d.ts +108 -56
- package/dist/index.js +4 -3
- package/dist/{ip2proxy-DAYO7EKZ.js → ip2proxy-OBCG6X6J.js} +35 -42
- package/dist/{ipgeolocation_io-XD4PSLII.js → ipgeolocation_io-NHH3DTQW.js} +40 -60
- package/dist/{ipqualityscore-K27QEAWK.js → ipqualityscore-7POMCBEC.js} +30 -42
- package/dist/{jina_ai-E6UXFV2P.js → jina_ai-YXVKROV4.js} +32 -58
- package/dist/{jira-ZDSXGQ6W.js → jira-LADO3VJU.js} +116 -126
- package/dist/{langsmith-TIFJRREW.js → langsmith-XZ6UAQFU.js} +101 -121
- package/dist/{lemlist-DASEMJMA.js → lemlist-P74GLNE7.js} +57 -68
- package/dist/{linear-KE6UP4SP.js → linear-CXJ7D37A.js} +109 -118
- package/dist/{logsnag-IMNDN4R5.js → logsnag-EVVHWFLK.js} +31 -48
- package/dist/main.js +103 -102
- package/dist/{mattermost-HHHMUXQA.js → mattermost-WG2MRGBD.js} +45 -62
- package/dist/{mem0-D2FGGOIY.js → mem0-HQWUKG6U.js} +72 -98
- package/dist/{memos-4OVIGFPH.js → memos-SQMJIFOE.js} +68 -122
- package/dist/{metabase-33WCX5YD.js → metabase-E27G2DZI.js} +47 -60
- package/dist/{mistral_ai-QIMZ2JYL.js → mistral_ai-MIL63NIT.js} +35 -40
- package/dist/{mother_duck-M6VWS2VH.js → mother_duck-AIZVCBNR.js} +42 -62
- package/dist/{ngrok-Z2PKQBHH.js → ngrok-XS4DVIQS.js} +42 -58
- package/dist/{notes-SS4RPC4K.js → notes-JEOUSL2Y.js} +3 -5
- package/dist/{notion-FJCNQ6I7.js → notion-U4EZVDW2.js} +83 -97
- package/dist/{open_exchange_rates-WU57WTT5.js → open_exchange_rates-AZSQEYEJ.js} +35 -39
- package/dist/{openai-JODZ4GKT.js → openai-HW3SYMTQ.js} +51 -55
- package/dist/{opengraph_io-SQRAUSV5.js → opengraph_io-QX74MAEL.js} +61 -79
- package/dist/{openrouter-Q5XXEJZ7.js → openrouter-OXSKYL6N.js} +41 -55
- package/dist/{outline-RT2EHJ2X.js → outline-CCQAPDSW.js} +89 -104
- package/dist/{paddle-OF2V7GAC.js → paddle-6KQPSSCK.js} +34 -49
- package/dist/{perplexity-LNZEWLHG.js → perplexity-2TXO7IQE.js} +33 -50
- package/dist/{pinecone-JSJIXZYN.js → pinecone-YOO7NULI.js} +65 -91
- package/dist/{pipedrive-D4CKVUXR.js → pipedrive-Q6RIFIFP.js} +37 -59
- package/dist/{polar-M7ZYP6UR.js → polar-KUMGCES3.js} +43 -53
- package/dist/{posthog-YV7CZOH4.js → posthog-VXQHBSMB.js} +58 -77
- package/dist/{postmark-KYHLECRG.js → postmark-YLIPF52S.js} +52 -71
- package/dist/{prerender-HCMHBKV2.js → prerender-CRY7UJN5.js} +32 -50
- package/dist/{pubmed-WYVLCCN3.js → pubmed-3Z4T5AM7.js} +28 -60
- package/dist/{railway-TWIRD5KR.js → railway-BP37IGFL.js} +32 -39
- package/dist/{readwise-UZ467IQ7.js → readwise-HTKICF4K.js} +62 -78
- package/dist/{render-MECUC5CC.js → render-WIVTUXJH.js} +48 -64
- package/dist/{replicate-A5MEK3SW.js → replicate-JJYPA43D.js} +41 -58
- package/dist/{resend-BC6EAWJQ.js → resend-TKHZVG7A.js} +27 -37
- package/dist/{rootly-ZM3QDUIS.js → rootly-FRSZLG5U.js} +64 -76
- package/dist/{scrapfly-WAML42QJ.js → scrapfly-M5WXGQWE.js} +45 -51
- package/dist/{scrapingbee-DG7PET3V.js → scrapingbee-PMXNLLBK.js} +25 -33
- package/dist/{screenshot_fyi-HY6WTHIO.js → screenshot_fyi-HFW4TAOH.js} +29 -47
- package/dist/{semantic_scholar-C5IZA7IP.js → semantic_scholar-KXVH2VZQ.js} +37 -56
- package/dist/{sentry-OKBPSTDM.js → sentry-WWOT2LRX.js} +66 -85
- package/dist/{shodan-PPC6DYU4.js → shodan-FY635H35.js} +42 -53
- package/dist/{shopify-EWGUHBXO.js → shopify-HQLBVSA5.js} +32 -49
- package/dist/{stripe-6RPDPC5W.js → stripe-GJN2GOHB.js} +4 -5
- package/dist/{supabase-SK7DQ42N.js → supabase-BBNZGQU6.js} +69 -88
- package/dist/{tavily-YCG5VQMH.js → tavily-DPENIBOG.js} +37 -62
- package/dist/{telegram-2OES5FYB.js → telegram-L4NONG6H.js} +168 -177
- package/dist/{telnyx-POOSBBR4.js → telnyx-H67MAEZS.js} +30 -50
- package/dist/{todoist-M7YD6YSS.js → todoist-G2BSP4DX.js} +77 -89
- package/dist/{trello-IS6V5W3E.js → trello-7WMVFDG2.js} +108 -122
- package/dist/{turso-RCFHUFVH.js → turso-ZUAESFC2.js} +52 -64
- package/dist/{twilio-OS2RXFGO.js → twilio-EYFYIX3B.js} +48 -55
- package/dist/{umami-PQ2SJ2LN.js → umami-AXAUDUVF.js} +49 -69
- package/dist/{unsplash-C6BPZO4E.js → unsplash-UCQAWPLR.js} +35 -52
- package/dist/{upstash_redis-WH6UER7H.js → upstash_redis-ZPZ4ASU6.js} +28 -40
- package/dist/{uptimerobot-M3YZGS6Z.js → uptimerobot-4QVKKUD5.js} +11 -12
- package/dist/{v2ex-R4JWTEHN.js → v2ex-VGEFJTYC.js} +36 -61
- package/dist/{vercel-FZVYUOQD.js → vercel-JME4TSCN.js} +124 -150
- package/dist/{webapi-VLM4IKVB.js → webapi-GW5QXWXE.js} +1 -1
- package/dist/{wolfram_alpha_api-2KOLO5DC.js → wolfram_alpha_api-TRGU2MDG.js} +26 -34
- package/dist/{wordpress-XRWGO6LG.js → wordpress-WRUKLCZR.js} +87 -104
- package/dist/{workos-WR4NKOYL.js → workos-ZDW4EHS4.js} +37 -56
- package/dist/{zhihu-BKZIB3WA.js → zhihu-4VI67CWU.js} +35 -57
- package/package.json +3 -3
- package/dist/chunk-2O27H4Y2.js +0 -183
- package/dist/chunk-GKX72JMJ.js +0 -378
- package/dist/chunk-MLKGABMK.js +0 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as z from './v4/classic/external.cjs';
|
|
2
2
|
import * as http from 'node:http';
|
|
3
3
|
import { Sql } from 'postgres';
|
|
4
4
|
import { Hono } from 'hono';
|
|
@@ -530,6 +530,50 @@ interface ContextProvider {
|
|
|
530
530
|
write?(path: string, entry: ContextEntryInput): Promise<ContextEntryMeta>;
|
|
531
531
|
}
|
|
532
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Tool Layer 的中立类型。
|
|
535
|
+
*
|
|
536
|
+
* `ToolSpec` 是**上游工具的中立形状**:mcp(`tools/list` 的 `Tool`)与 http
|
|
537
|
+
* (`HttpToolDef`)都归一到它,虚拟化(virtualize.ts)与 `~help` 派生(mcpSchema.ts)
|
|
538
|
+
* 只认 `ToolSpec`,不感知上游是 mcp 还是 http。它把 `ToolMeta`+`ToolDef`
|
|
539
|
+
* 合并为一个形状:`description` 可缺省(上游可能不带),另携 `confirm`(危险工具二次确认)。
|
|
540
|
+
*/
|
|
541
|
+
/** 上游工具的中立形状(mcp/http 归一目标)。 */
|
|
542
|
+
interface ToolSpec {
|
|
543
|
+
/** 危险操作二次确认;进 `~help` 的 confirm 行。 */
|
|
544
|
+
confirm?: boolean;
|
|
545
|
+
/** 一句话描述;进 `~help` 的 `h` 行。上游可能不带 → 可缺省。 */
|
|
546
|
+
description?: string;
|
|
547
|
+
/** 副作用标记(read/write/destructive);进 `~help` 的 effect 行。 */
|
|
548
|
+
effect?: string;
|
|
549
|
+
/** JSON Schema;`~help` 的 body 数据源。 */
|
|
550
|
+
inputSchema?: unknown;
|
|
551
|
+
/** 工具名(虚拟化前为上游原名,虚拟化后为对外虚拟名)。 */
|
|
552
|
+
name: string;
|
|
553
|
+
/**
|
|
554
|
+
* 返回值的 JSON Schema(可选)。与 `inputSchema` 对称,同为裸 JSON Schema。
|
|
555
|
+
*
|
|
556
|
+
* 来源:MCP 上游的 `Tool.outputSchema`、plugin 作者在 `OperationSpec.outputSchema` 里的声明。
|
|
557
|
+
* 去处:工具级全量 `~help`(JSON 的 `outputSchema` / DSL 的 `result` 行)与 MCP consumer 端点。
|
|
558
|
+
* 索引形态的 `~help` 不含它(同 inputSchema,两级披露)。
|
|
559
|
+
*/
|
|
560
|
+
outputSchema?: unknown;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* 工具调用结果。`isError:true` 是**工具业务级错误**(上游 HTTP 200
|
|
564
|
+
* 正常返回、内容为错),按内容协商渲染——**不是** TBError(传输/协议错误才归一为
|
|
565
|
+
* TBError,见 upstreamError.ts)。
|
|
566
|
+
*/
|
|
567
|
+
interface ToolResult {
|
|
568
|
+
/** markdown 文本或结构化 JSON(按内容协商输出)。 */
|
|
569
|
+
content: string | unknown;
|
|
570
|
+
/** MCP 等上游的原生多模态 content blocks;HTBP 渲染仍使用归一后的 content。 */
|
|
571
|
+
contentBlocks?: unknown[];
|
|
572
|
+
isError?: boolean;
|
|
573
|
+
/** MCP 上游返回的结构化结果;consumer endpoint 转发时保留。 */
|
|
574
|
+
structuredContent?: Record<string, unknown>;
|
|
575
|
+
}
|
|
576
|
+
|
|
533
577
|
/**
|
|
534
578
|
* DeviceFrame:设备 WS 帧协议的类型与编解码。
|
|
535
579
|
*
|
|
@@ -588,51 +632,23 @@ type DeviceCallResult = {
|
|
|
588
632
|
ok: false;
|
|
589
633
|
};
|
|
590
634
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
/** 副作用标记(read/write/destructive);进 `~help` 的 effect 行。 */
|
|
606
|
-
effect?: string;
|
|
607
|
-
/** JSON Schema;`~help` 的 body 数据源。 */
|
|
608
|
-
inputSchema?: unknown;
|
|
609
|
-
/** 工具名(虚拟化前为上游原名,虚拟化后为对外虚拟名)。 */
|
|
610
|
-
name: string;
|
|
611
|
-
/**
|
|
612
|
-
* 返回值的 JSON Schema(可选)。与 `inputSchema` 对称,同为裸 JSON Schema。
|
|
613
|
-
*
|
|
614
|
-
* 来源:MCP 上游的 `Tool.outputSchema`、plugin 作者在 `OperationSpec.outputSchema` 里的声明。
|
|
615
|
-
* 去处:工具级全量 `~help`(JSON 的 `outputSchema` / DSL 的 `result` 行)与 MCP consumer 端点。
|
|
616
|
-
* 索引形态的 `~help` 不含它(同 inputSchema,两级披露)。
|
|
617
|
-
*/
|
|
618
|
-
outputSchema?: unknown;
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* 工具调用结果。`isError:true` 是**工具业务级错误**(上游 HTTP 200
|
|
622
|
-
* 正常返回、内容为错),按内容协商渲染——**不是** TBError(传输/协议错误才归一为
|
|
623
|
-
* TBError,见 upstreamError.ts)。
|
|
624
|
-
*/
|
|
625
|
-
interface ToolResult {
|
|
626
|
-
/** markdown 文本或结构化 JSON(按内容协商输出)。 */
|
|
627
|
-
content: string | unknown;
|
|
628
|
-
/** MCP 等上游的原生多模态 content blocks;HTBP 渲染仍使用归一后的 content。 */
|
|
629
|
-
contentBlocks?: unknown[];
|
|
630
|
-
isError?: boolean;
|
|
631
|
-
/** MCP 上游返回的结构化结果;consumer endpoint 转发时保留。 */
|
|
632
|
-
structuredContent?: Record<string, unknown>;
|
|
635
|
+
interface RuntimeRemoteSettings {
|
|
636
|
+
allowInsecure: boolean;
|
|
637
|
+
allowlist: string[];
|
|
638
|
+
federatedSearch?: {
|
|
639
|
+
maxConcurrency?: number;
|
|
640
|
+
maxResponseBodyBytes?: number;
|
|
641
|
+
maxSources?: number;
|
|
642
|
+
minChildWorkMs?: number;
|
|
643
|
+
perHopReturnReserveMs?: number;
|
|
644
|
+
sessionTtlMs?: number;
|
|
645
|
+
totalDeadlineMs?: number;
|
|
646
|
+
};
|
|
647
|
+
instanceId?: string;
|
|
648
|
+
maxHops: number;
|
|
633
649
|
}
|
|
634
650
|
|
|
635
|
-
type SearchCapability = 'search' | 'search:semantic';
|
|
651
|
+
type SearchCapability = 'search' | 'search:federated' | 'search:semantic';
|
|
636
652
|
/** 全局工具搜索的完整结果;只在权限和可见性候选筛选后 hydrate。 */
|
|
637
653
|
interface ToolSearchHit {
|
|
638
654
|
path: TreePath;
|
|
@@ -640,26 +656,48 @@ interface ToolSearchHit {
|
|
|
640
656
|
}
|
|
641
657
|
/** adapter 返回的轻量候选;resumeOffset 仅在当前请求内传递,不暴露给协议调用方。 */
|
|
642
658
|
interface ToolSearchCandidate {
|
|
659
|
+
/** 命中的原始 logical terms / 全部原始 logical terms;不按派生 unit 重复计数。 */
|
|
660
|
+
coverage: number;
|
|
661
|
+
matchedTermCount: number;
|
|
643
662
|
name: string;
|
|
644
663
|
path: TreePath;
|
|
645
664
|
ref: string;
|
|
646
665
|
resumeOffset: number;
|
|
647
666
|
revision: number;
|
|
667
|
+
/** 仅供宿主在 canonical hydration 提前截页时续签同一搜索约束,不进入 wire。 */
|
|
668
|
+
searchOptionsFingerprint?: string;
|
|
669
|
+
totalTermCount: number;
|
|
648
670
|
}
|
|
671
|
+
type ToolSearchEffect = 'destructive' | 'read' | 'unknown' | 'write';
|
|
672
|
+
type ToolSearchMatching = 'all' | 'best';
|
|
649
673
|
interface ToolSearchOptions {
|
|
650
674
|
cursor?: string;
|
|
675
|
+
effects?: ToolSearchEffect[];
|
|
651
676
|
limit?: number;
|
|
677
|
+
matching?: ToolSearchMatching;
|
|
678
|
+
minCoverage?: number;
|
|
652
679
|
mode?: 'keyword' | 'semantic';
|
|
680
|
+
pathPrefix?: TreePath;
|
|
681
|
+
}
|
|
682
|
+
/** 会改变候选集合或分页档位的规范化约束;cursor 必须绑定其完整指纹。 */
|
|
683
|
+
interface NormalizedToolSearchOptions {
|
|
684
|
+
effects?: ToolSearchEffect[];
|
|
685
|
+
matching: ToolSearchMatching;
|
|
686
|
+
minCoverage?: number;
|
|
687
|
+
pathPrefix?: TreePath;
|
|
653
688
|
}
|
|
654
689
|
/** 宿主提供的全局工具索引;权限和虚拟化仍由 gateway 处理。 */
|
|
655
690
|
interface SearchIndex {
|
|
656
691
|
readonly capabilities: readonly SearchCapability[];
|
|
657
692
|
cursorFor(query: string, candidate: ToolSearchCandidate, mode?: 'keyword' | 'semantic'): Promise<string>;
|
|
693
|
+
/** 联邦 continuation 的 topology binding;不实现的自定义 adapter 只能提供 local search。 */
|
|
694
|
+
revision?(): Promise<number | string>;
|
|
658
695
|
search(query: string, opts?: ToolSearchOptions): Promise<Page<ToolSearchCandidate>>;
|
|
659
696
|
}
|
|
660
697
|
/** 索引持久层使用的轻量记录;完整 ToolSpec 只保留摘要,不进入派生数据库。 */
|
|
661
698
|
interface SerializedToolSearchRecord {
|
|
662
699
|
description: string;
|
|
700
|
+
effect: ToolSearchEffect;
|
|
663
701
|
feedback: string;
|
|
664
702
|
name: string;
|
|
665
703
|
path: TreePath;
|
|
@@ -745,7 +783,7 @@ interface SqlSearchDialect {
|
|
|
745
783
|
* 把已 normalize 的 query 变成候选查询语句(含排序与分页)。三后端共用查询单元
|
|
746
784
|
* 展开和评分形态,方言只选择占位符语法与 LIKE/ILIKE。
|
|
747
785
|
*/
|
|
748
|
-
candidateStatement(query: string, limit: number, offset: number): SqlSearchStatement;
|
|
786
|
+
candidateStatement(query: string, limit: number, offset: number, constraints?: NormalizedToolSearchOptions): SqlSearchStatement;
|
|
749
787
|
/** 建表(幂等),元素不带尾分号。 */
|
|
750
788
|
readonly schemaStatements: readonly string[];
|
|
751
789
|
/** 编排直接下发的固定语句。 */
|
|
@@ -786,6 +824,7 @@ declare class SqlSearchIndex implements MutableSearchIndex {
|
|
|
786
824
|
private meta;
|
|
787
825
|
private snapshotDigests;
|
|
788
826
|
initialized(): Promise<boolean>;
|
|
827
|
+
revision(): Promise<number>;
|
|
789
828
|
replace(path: TreePath, tools: readonly ToolSpec[], opts?: {
|
|
790
829
|
feedback?: string;
|
|
791
830
|
}): Promise<void>;
|
|
@@ -851,18 +890,30 @@ interface RemoteSettings {
|
|
|
851
890
|
allowInsecure: boolean;
|
|
852
891
|
/** baseUrl 的 host 后缀白名单;空数组 = 拒一切 remote。 */
|
|
853
892
|
allowlist: string[];
|
|
893
|
+
/** 联邦 search 的部署级硬上限;客户端与下游 header 只能进一步收紧。 */
|
|
894
|
+
federatedSearch?: Partial<FederatedSearchSettings>;
|
|
854
895
|
/** 本实例 X-TB-Via 标识;缺省用**入站请求 host** 派生(跨实例联邦须显式配置才能可靠去环)。 */
|
|
855
896
|
instanceId?: string;
|
|
856
897
|
/** X-TB-Via 跳数上限(缺省 4,由宿主适配层落默认)。 */
|
|
857
898
|
maxHops: number;
|
|
858
899
|
}
|
|
900
|
+
interface FederatedSearchSettings {
|
|
901
|
+
maxConcurrency: number;
|
|
902
|
+
maxResponseBodyBytes: number;
|
|
903
|
+
maxSources: number;
|
|
904
|
+
minChildWorkMs: number;
|
|
905
|
+
perHopReturnReserveMs: number;
|
|
906
|
+
sessionTtlMs: number;
|
|
907
|
+
totalDeadlineMs: number;
|
|
908
|
+
}
|
|
859
909
|
|
|
860
910
|
/**
|
|
861
911
|
* 宿主注入面与请求期公共类型。
|
|
862
912
|
*
|
|
863
|
-
*
|
|
864
|
-
* Provider
|
|
865
|
-
* toolNodes/contextNodes/helpModel 与 routes
|
|
913
|
+
* 这里只放形状:五个数据/设备注入点(state / objects / secrets / device / search)、
|
|
914
|
+
* Provider OAuth 安全出站通道、进程内 Provider 钩子与解析后的部署配置。行为实现
|
|
915
|
+
* 分散在 paths/federation/deviceNodes/toolNodes/contextNodes/helpModel 与 routes/*,
|
|
916
|
+
* 装配在 tbApp.ts。
|
|
866
917
|
*/
|
|
867
918
|
|
|
868
919
|
/** 帧协议 call 转发的入参(id 由调用点生成,幂等键)。 */
|
|
@@ -901,7 +952,7 @@ interface ReadinessReport {
|
|
|
901
952
|
ready: boolean;
|
|
902
953
|
}
|
|
903
954
|
/**
|
|
904
|
-
* tb app 的宿主注入面(
|
|
955
|
+
* tb app 的宿主注入面(数据/设备五注入点 + 安全出站通道 + 解析后的部署配置)。
|
|
905
956
|
* 核心业务逻辑零分叉:Workers 适配层(app.ts)与 SDK(packages/sdk)都注入此形状。
|
|
906
957
|
*/
|
|
907
958
|
interface TbAppDeps {
|
|
@@ -941,6 +992,12 @@ interface TbAppDeps {
|
|
|
941
992
|
* 那个插件解析不出 export;反之则解析得出但调不动(unavailable)。宿主该两者同源装配。
|
|
942
993
|
*/
|
|
943
994
|
pluginCatalog?: BuiltinCatalog;
|
|
995
|
+
/**
|
|
996
|
+
* Provider OAuth 令牌端点的宿主出站通道。必须由宿主显式注入;缺省时 OAuth
|
|
997
|
+
* 发起、回调兑换与 access-token 解析全部 fail closed,绝不回退到全局 fetch。
|
|
998
|
+
* 标准宿主注入逐跳校验且拒绝跨源 body 重定向的 guarded fetch。
|
|
999
|
+
*/
|
|
1000
|
+
providerOAuthFetch?: typeof fetch;
|
|
944
1001
|
/**
|
|
945
1002
|
* 后端连通性探测(GET /readyz;k8s readiness)。宿主注入闭包,自行探测其长连接
|
|
946
1003
|
* 后端(PG 池 / Redis)并叠加 draining 状态。缺省 → /readyz 恒 200:请求期绑定
|
|
@@ -1003,7 +1060,7 @@ declare function createTbApp(deps: TbAppDeps): Hono<{
|
|
|
1003
1060
|
* Node 宿主的 env 配置面。变量名与语义对齐 CF 宿主(gateway/src/app.ts 的 Env),
|
|
1004
1061
|
* 仅新增宿主形态相关的 TB_PORT / TB_HOST / TB_DATA_DIR / TB_UI_DIR / TB_DATABASE_URL。
|
|
1005
1062
|
* 端口额外兜底平台注入的 PORT(PaaS 通行约定)。
|
|
1006
|
-
*
|
|
1063
|
+
* Node/Workers 共用字段由 core runtimeEnv Zod schema 解析,本文件只保留 Node 宿主字段。
|
|
1007
1064
|
*/
|
|
1008
1065
|
|
|
1009
1066
|
interface ServerConfig {
|
|
@@ -1066,12 +1123,7 @@ interface ServerConfig {
|
|
|
1066
1123
|
redisUrl?: string;
|
|
1067
1124
|
refThresholdBytes?: number;
|
|
1068
1125
|
refTtlSec?: number;
|
|
1069
|
-
remote:
|
|
1070
|
-
allowInsecure: boolean;
|
|
1071
|
-
allowlist: string[];
|
|
1072
|
-
instanceId?: string;
|
|
1073
|
-
maxHops: number;
|
|
1074
|
-
};
|
|
1126
|
+
remote: RuntimeRemoteSettings;
|
|
1075
1127
|
/**
|
|
1076
1128
|
* 本副本标识(TB_REPLICA_ID),路由表的 value。缺省用 hostname —— 容器平台上
|
|
1077
1129
|
* 每个副本的 hostname 天然唯一;同机多进程需显式区分。
|
package/dist/index.js
CHANGED
|
@@ -12,9 +12,10 @@ import {
|
|
|
12
12
|
configFromEnv,
|
|
13
13
|
createDataObjectStore,
|
|
14
14
|
createTbServer
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-CLEZ6YQ6.js";
|
|
16
|
+
import "./chunk-SWBNHIO4.js";
|
|
17
|
+
import "./chunk-OKRZPQ3R.js";
|
|
18
|
+
import "./chunk-U67V476Y.js";
|
|
18
19
|
export {
|
|
19
20
|
DEVICE_FORWARD_TIMEOUT_MS,
|
|
20
21
|
DEVICE_ROUTE_TTL_SEC,
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProviderHttpClient
|
|
3
|
+
} from "./chunk-VLOIDU5U.js";
|
|
4
|
+
import "./chunk-JXHMDBAY.js";
|
|
1
5
|
import {
|
|
2
6
|
createProviderPlugin,
|
|
3
7
|
requireApiKey,
|
|
4
8
|
upstreamError
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import
|
|
7
|
-
guardedFetch
|
|
8
|
-
} from "./chunk-2O27H4Y2.js";
|
|
9
|
-
import "./chunk-GKX72JMJ.js";
|
|
9
|
+
} from "./chunk-B4P6YZFS.js";
|
|
10
|
+
import "./chunk-SWBNHIO4.js";
|
|
10
11
|
import {
|
|
11
12
|
TBError,
|
|
12
13
|
external_exports
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-OKRZPQ3R.js";
|
|
15
|
+
import "./chunk-U67V476Y.js";
|
|
15
16
|
|
|
16
17
|
// ../plugins/src/ip2proxy/schema.ts
|
|
17
18
|
var lookupIpInput = external_exports.strictObject({
|
|
@@ -48,55 +49,47 @@ var ip2proxyActions = {
|
|
|
48
49
|
// ../plugins/src/ip2proxy/api.ts
|
|
49
50
|
var SERVICE = "ip2proxy";
|
|
50
51
|
var API_BASE = "https://api.ip2proxy.com";
|
|
52
|
+
var http = createProviderHttpClient({ baseUrl: `${API_BASE}/`, service: SERVICE });
|
|
51
53
|
var DEFAULT_PACKAGE = "PX1";
|
|
52
|
-
async function readPayload(response) {
|
|
53
|
-
const body = await response.text();
|
|
54
|
-
if (body === "") return null;
|
|
55
|
-
try {
|
|
56
|
-
return JSON.parse(body);
|
|
57
|
-
} catch {
|
|
58
|
-
return body;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
54
|
function payloadError(payload) {
|
|
62
55
|
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return void 0;
|
|
63
56
|
const message = payload.response;
|
|
64
57
|
if (typeof message !== "string" || message === "" || message === "OK") return void 0;
|
|
65
58
|
return message;
|
|
66
59
|
}
|
|
60
|
+
function classifiedPayloadError(message) {
|
|
61
|
+
const lower = message.toLowerCase();
|
|
62
|
+
return upstreamError(lower.includes("api key") || lower.includes("credit") ? 401 : 502, message);
|
|
63
|
+
}
|
|
67
64
|
async function lookupIp(input, ctx) {
|
|
68
65
|
if (input.ip === void 0 || input.ip === "") {
|
|
69
66
|
throw new TBError("invalid_argument", "ip \u4E0D\u80FD\u4E3A\u7A7A");
|
|
70
67
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
68
|
+
const result = await http.request({
|
|
69
|
+
path: "/",
|
|
70
|
+
method: "GET",
|
|
71
|
+
query: [
|
|
72
|
+
["key", requireApiKey(ctx, SERVICE)],
|
|
73
|
+
["format", "json"],
|
|
74
|
+
["ip", input.ip],
|
|
75
|
+
["package", input.package ?? DEFAULT_PACKAGE]
|
|
76
|
+
],
|
|
77
|
+
headers: { accept: "application/json" },
|
|
78
|
+
invalidJson: "text",
|
|
79
|
+
mapError: ({ data: payload2, status, statusText }) => {
|
|
80
|
+
const failure2 = payloadError(payload2);
|
|
81
|
+
if (failure2 !== void 0) return classifiedPayloadError(failure2);
|
|
82
|
+
return upstreamError(status || 500, statusText || "IP2Proxy request failed");
|
|
83
|
+
},
|
|
84
|
+
mapTransportError: ({ message }) => new TBError(
|
|
86
85
|
"unavailable",
|
|
87
|
-
|
|
86
|
+
message === void 0 ? "IP2Proxy \u8BF7\u6C42\u5931\u8D25" : `IP2Proxy \u8BF7\u6C42\u5931\u8D25: ${message}`,
|
|
88
87
|
{ retryable: true }
|
|
89
|
-
)
|
|
90
|
-
}
|
|
88
|
+
)
|
|
89
|
+
});
|
|
90
|
+
const payload = result.bodyKind === "empty" ? null : result.data;
|
|
91
91
|
const failure = payloadError(payload);
|
|
92
|
-
if (failure !== void 0)
|
|
93
|
-
const lower = failure.toLowerCase();
|
|
94
|
-
const credentialIssue = lower.includes("api key") || lower.includes("credit");
|
|
95
|
-
throw upstreamError(credentialIssue ? 401 : 502, failure);
|
|
96
|
-
}
|
|
97
|
-
if (!response.ok) {
|
|
98
|
-
throw upstreamError(response.status || 500, response.statusText || "IP2Proxy request failed");
|
|
99
|
-
}
|
|
92
|
+
if (failure !== void 0) throw classifiedPayloadError(failure);
|
|
100
93
|
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
101
94
|
throw new TBError("unavailable", "IP2Proxy \u8FD4\u56DE\u7684\u4E0D\u662F JSON \u5BF9\u8C61", { retryable: true });
|
|
102
95
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProviderHttpClient
|
|
3
|
+
} from "./chunk-VLOIDU5U.js";
|
|
4
|
+
import {
|
|
5
|
+
asJsonObject
|
|
6
|
+
} from "./chunk-JXHMDBAY.js";
|
|
1
7
|
import {
|
|
2
8
|
createProviderPlugin,
|
|
3
9
|
requireApiKey,
|
|
4
10
|
upstreamError
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import
|
|
7
|
-
guardedFetch
|
|
8
|
-
} from "./chunk-2O27H4Y2.js";
|
|
9
|
-
import "./chunk-GKX72JMJ.js";
|
|
11
|
+
} from "./chunk-B4P6YZFS.js";
|
|
12
|
+
import "./chunk-SWBNHIO4.js";
|
|
10
13
|
import {
|
|
11
|
-
TBError,
|
|
12
14
|
external_exports
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-OKRZPQ3R.js";
|
|
16
|
+
import "./chunk-U67V476Y.js";
|
|
15
17
|
|
|
16
18
|
// ../plugins/src/ipgeolocation_io/api.ts
|
|
17
19
|
var SERVICE = "ipgeolocation_io";
|
|
18
20
|
var API_BASE = "https://api.ipgeolocation.io/";
|
|
19
21
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
20
|
-
|
|
21
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
22
|
-
}
|
|
22
|
+
var http = createProviderHttpClient({ baseUrl: API_BASE, service: SERVICE });
|
|
23
23
|
function nullableString(value) {
|
|
24
24
|
if (typeof value === "string") return value;
|
|
25
25
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
@@ -39,47 +39,27 @@ function nullableInteger(value) {
|
|
|
39
39
|
}
|
|
40
40
|
function errorMessage(payload, status) {
|
|
41
41
|
if (typeof payload === "string" && payload.trim() !== "") return payload;
|
|
42
|
-
const record =
|
|
42
|
+
const record = asJsonObject(payload);
|
|
43
43
|
const message = record?.message ?? record?.error;
|
|
44
44
|
if (typeof message === "string" && message.trim() !== "") return message;
|
|
45
45
|
return `IPGeolocation.io request failed with status ${status}`;
|
|
46
46
|
}
|
|
47
|
-
async function readPayload(response) {
|
|
48
|
-
const body = await response.text();
|
|
49
|
-
if (body.trim() === "") return null;
|
|
50
|
-
try {
|
|
51
|
-
return JSON.parse(body);
|
|
52
|
-
} catch {
|
|
53
|
-
throw upstreamError(502, "IPGeolocation.io returned invalid JSON");
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
47
|
async function request(ctx, path, params) {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
throw upstreamError(504, "IPGeolocation.io request timed out");
|
|
73
|
-
}
|
|
74
|
-
throw error;
|
|
75
|
-
}
|
|
76
|
-
const payload = await readPayload(response);
|
|
77
|
-
if (!response.ok) {
|
|
78
|
-
const status = response.status;
|
|
79
|
-
const normalized = status === 429 || status === 401 || status === 403 ? status : status >= 400 && status < 500 ? 400 : status || 500;
|
|
80
|
-
throw upstreamError(normalized, errorMessage(payload, status));
|
|
81
|
-
}
|
|
82
|
-
const record = toRecord(payload);
|
|
48
|
+
const { data: payload } = await http.request({
|
|
49
|
+
path,
|
|
50
|
+
method: "GET",
|
|
51
|
+
query: [["apiKey", requireApiKey(ctx, SERVICE)], ...Object.entries(params)],
|
|
52
|
+
headers: { accept: "application/json" },
|
|
53
|
+
timeoutMs: REQUEST_TIMEOUT_MS,
|
|
54
|
+
invalidJsonMessage: "IPGeolocation.io returned invalid JSON",
|
|
55
|
+
mapError: ({ bodyKind, data, status }) => {
|
|
56
|
+
if (bodyKind === "invalid-json") return upstreamError(502, "IPGeolocation.io returned invalid JSON");
|
|
57
|
+
const normalized = status === 429 || status === 401 || status === 403 ? status : status >= 400 && status < 500 ? 400 : status || 500;
|
|
58
|
+
return upstreamError(normalized, errorMessage(data, status));
|
|
59
|
+
},
|
|
60
|
+
mapTransportError: ({ kind }) => kind === "timeout" ? upstreamError(504, "IPGeolocation.io request timed out") : upstreamError(502, "IPGeolocation.io request failed")
|
|
61
|
+
});
|
|
62
|
+
const record = asJsonObject(payload);
|
|
83
63
|
if (record === void 0) throw upstreamError(502, "IPGeolocation.io returned an invalid payload");
|
|
84
64
|
return record;
|
|
85
65
|
}
|
|
@@ -106,7 +86,7 @@ async function lookupIp(input, ctx) {
|
|
|
106
86
|
excludes: joinList(input.excludes),
|
|
107
87
|
include: includes.length > 0 ? includes.join(",") : void 0
|
|
108
88
|
});
|
|
109
|
-
const location =
|
|
89
|
+
const location = asJsonObject(payload.location) ?? payload;
|
|
110
90
|
return {
|
|
111
91
|
geolocation: {
|
|
112
92
|
ip: nullableString(payload.ip),
|
|
@@ -122,17 +102,17 @@ async function lookupIp(input, ctx) {
|
|
|
122
102
|
zipcode: nullableString(location.zipcode),
|
|
123
103
|
latitude: nullableNumber(location.latitude),
|
|
124
104
|
longitude: nullableNumber(location.longitude),
|
|
125
|
-
callingCode: nullableString(
|
|
105
|
+
callingCode: nullableString(asJsonObject(payload.country_metadata)?.calling_code),
|
|
126
106
|
countryFlag: nullableString(location.country_flag),
|
|
127
|
-
countryMetadata:
|
|
128
|
-
network:
|
|
129
|
-
asn:
|
|
130
|
-
company:
|
|
131
|
-
timeZone:
|
|
132
|
-
currency:
|
|
133
|
-
security:
|
|
134
|
-
abuse:
|
|
135
|
-
userAgent:
|
|
107
|
+
countryMetadata: asJsonObject(payload.country_metadata) ?? null,
|
|
108
|
+
network: asJsonObject(payload.network) ?? null,
|
|
109
|
+
asn: asJsonObject(payload.asn) ?? null,
|
|
110
|
+
company: asJsonObject(payload.company) ?? null,
|
|
111
|
+
timeZone: asJsonObject(payload.time_zone) ?? null,
|
|
112
|
+
currency: asJsonObject(payload.currency) ?? null,
|
|
113
|
+
security: asJsonObject(payload.security) ?? null,
|
|
114
|
+
abuse: asJsonObject(payload.abuse) ?? null,
|
|
115
|
+
userAgent: asJsonObject(payload.user_agent) ?? null,
|
|
136
116
|
raw: payload
|
|
137
117
|
}
|
|
138
118
|
};
|
|
@@ -163,7 +143,7 @@ async function getTimezone(input, ctx) {
|
|
|
163
143
|
yearAbbr: nullableString(payload.year_abbr),
|
|
164
144
|
isDst: typeof payload.is_dst === "boolean" ? payload.is_dst : null,
|
|
165
145
|
dstSavings: nullableInteger(payload.dst_savings),
|
|
166
|
-
geo:
|
|
146
|
+
geo: asJsonObject(payload.geo) ?? null,
|
|
167
147
|
raw: payload
|
|
168
148
|
}
|
|
169
149
|
};
|
|
@@ -178,7 +158,7 @@ async function getAstronomy(input, ctx) {
|
|
|
178
158
|
});
|
|
179
159
|
return {
|
|
180
160
|
astronomy: {
|
|
181
|
-
location:
|
|
161
|
+
location: asJsonObject(payload.location) ?? null,
|
|
182
162
|
date: nullableString(payload.date),
|
|
183
163
|
currentTime: nullableString(payload.current_time),
|
|
184
164
|
sunrise: nullableString(payload.sunrise),
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProviderHttpClient
|
|
3
|
+
} from "./chunk-VLOIDU5U.js";
|
|
4
|
+
import "./chunk-JXHMDBAY.js";
|
|
1
5
|
import {
|
|
2
6
|
createProviderPlugin,
|
|
3
7
|
requireApiKey,
|
|
4
8
|
upstreamError
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import
|
|
7
|
-
guardedFetch
|
|
8
|
-
} from "./chunk-2O27H4Y2.js";
|
|
9
|
-
import "./chunk-GKX72JMJ.js";
|
|
9
|
+
} from "./chunk-B4P6YZFS.js";
|
|
10
|
+
import "./chunk-SWBNHIO4.js";
|
|
10
11
|
import {
|
|
11
12
|
TBError,
|
|
12
13
|
external_exports
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-OKRZPQ3R.js";
|
|
15
|
+
import "./chunk-U67V476Y.js";
|
|
15
16
|
|
|
16
17
|
// ../plugins/src/ipqualityscore/api.ts
|
|
17
18
|
var SERVICE = "ipqualityscore";
|
|
18
19
|
var API_BASE = "https://www.ipqualityscore.com";
|
|
20
|
+
var http = createProviderHttpClient({ baseUrl: API_BASE, service: SERVICE });
|
|
19
21
|
var IP_LITERAL = external_exports.union([external_exports.ipv4(), external_exports.ipv6()]);
|
|
20
22
|
function optionalText(value) {
|
|
21
23
|
return value?.trim() || void 0;
|
|
@@ -32,55 +34,41 @@ function messageOf(payload) {
|
|
|
32
34
|
const pick = (value) => typeof value === "string" ? optionalText(value) : void 0;
|
|
33
35
|
return pick(record.message) ?? pick(record.error);
|
|
34
36
|
}
|
|
35
|
-
function ipqsError(
|
|
36
|
-
const message = messageOf(payload) ?? optionalText(
|
|
37
|
+
function ipqsError(status, statusText, payload) {
|
|
38
|
+
const message = messageOf(payload) ?? optionalText(statusText) ?? `IPQualityScore request failed with ${status}`;
|
|
37
39
|
const lower = message.toLowerCase();
|
|
38
|
-
if (
|
|
40
|
+
if (status === 429 || status === 402 || lower.includes("insufficient credits")) {
|
|
39
41
|
return upstreamError(429, message);
|
|
40
42
|
}
|
|
41
|
-
if (lower.includes("invalid api key") || lower.includes("api key") ||
|
|
43
|
+
if (lower.includes("invalid api key") || lower.includes("api key") || status === 401 || status === 403) {
|
|
42
44
|
return upstreamError(401, message);
|
|
43
45
|
}
|
|
44
|
-
if (
|
|
46
|
+
if (status === 400 || lower.includes("invalid ip") || lower.includes("invalid email") || lower.includes("invalid phone") || lower.includes("invalid url")) {
|
|
45
47
|
return upstreamError(400, message);
|
|
46
48
|
}
|
|
47
|
-
return upstreamError(
|
|
48
|
-
}
|
|
49
|
-
async function readPayload(response) {
|
|
50
|
-
const body = await response.text();
|
|
51
|
-
if (body === "") return null;
|
|
52
|
-
try {
|
|
53
|
-
return JSON.parse(body);
|
|
54
|
-
} catch {
|
|
55
|
-
return body;
|
|
56
|
-
}
|
|
49
|
+
return upstreamError(status >= 400 ? status : 502, message);
|
|
57
50
|
}
|
|
58
51
|
async function request(ctx, family, value, query = []) {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
headers: { accept: "application/json" }
|
|
70
|
-
});
|
|
71
|
-
payload = await readPayload(response);
|
|
72
|
-
} catch (error) {
|
|
73
|
-
throw new TBError(
|
|
52
|
+
const apiKey = requireApiKey(ctx, SERVICE);
|
|
53
|
+
const result = await http.request({
|
|
54
|
+
path: `/api/json/${family}/${encodeURIComponent(apiKey)}/${encodeURIComponent(value)}`,
|
|
55
|
+
method: "GET",
|
|
56
|
+
query,
|
|
57
|
+
headers: { accept: "application/json" },
|
|
58
|
+
invalidJson: "text",
|
|
59
|
+
sensitiveValues: [apiKey],
|
|
60
|
+
mapError: ({ data, status, statusText }) => ipqsError(status, statusText, data),
|
|
61
|
+
mapTransportError: ({ message }) => new TBError(
|
|
74
62
|
"unavailable",
|
|
75
|
-
|
|
63
|
+
message === void 0 ? "IPQualityScore \u8BF7\u6C42\u5931\u8D25" : `IPQualityScore \u8BF7\u6C42\u5931\u8D25: ${message}`,
|
|
76
64
|
{ retryable: true }
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
65
|
+
)
|
|
66
|
+
});
|
|
67
|
+
const payload = result.bodyKind === "empty" ? null : result.data;
|
|
80
68
|
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
81
69
|
throw new TBError("unavailable", `IPQualityScore \u5BF9 ${family} \u7684\u54CD\u5E94\u4E0D\u662F JSON \u5BF9\u8C61`, { retryable: true });
|
|
82
70
|
}
|
|
83
|
-
if (payload.success === false) throw ipqsError(
|
|
71
|
+
if (payload.success === false) throw ipqsError(result.status, result.statusText, payload);
|
|
84
72
|
return payload;
|
|
85
73
|
}
|
|
86
74
|
async function checkIpReputation(input, ctx) {
|