@harrylabsj/kiwi 0.7.22 → 0.9.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/README.md +45 -10
- package/dist/a2a/negotiate.d.ts +6 -2
- package/dist/a2a/negotiate.js +10 -3
- package/dist/a2a/negotiate.js.map +1 -1
- package/dist/a2a/node.d.ts +4 -1
- package/dist/a2a/node.js +57 -4
- package/dist/a2a/node.js.map +1 -1
- package/dist/a2a/server/merchant-handler.d.ts +11 -3
- package/dist/a2a/server/merchant-handler.js +84 -26
- package/dist/a2a/server/merchant-handler.js.map +1 -1
- package/dist/agent/buyer/buyer-tools.js +17 -10
- package/dist/agent/buyer/buyer-tools.js.map +1 -1
- package/dist/agent/buyer/scheduler.d.ts +1 -0
- package/dist/agent/buyer/scheduler.js +5 -1
- package/dist/agent/buyer/scheduler.js.map +1 -1
- package/dist/agent/buyer/task-store.js +5 -2
- package/dist/agent/buyer/task-store.js.map +1 -1
- package/dist/agent/chat-tools.js +10 -3
- package/dist/agent/chat-tools.js.map +1 -1
- package/dist/agent/context/fencing.d.ts +27 -0
- package/dist/agent/context/fencing.js +126 -0
- package/dist/agent/context/fencing.js.map +1 -0
- package/dist/agent/context/grounding.d.ts +18 -0
- package/dist/agent/context/grounding.js +22 -0
- package/dist/agent/context/grounding.js.map +1 -0
- package/dist/agent/host/events.d.ts +31 -0
- package/dist/agent/host/events.js +62 -0
- package/dist/agent/host/events.js.map +1 -0
- package/dist/agent/host/tui-renderer.d.ts +17 -0
- package/dist/agent/host/tui-renderer.js +125 -0
- package/dist/agent/host/tui-renderer.js.map +1 -0
- package/dist/agent/host/web-renderer.d.ts +71 -0
- package/dist/agent/host/web-renderer.js +185 -0
- package/dist/agent/host/web-renderer.js.map +1 -0
- package/dist/agent/kernel-builder.d.ts +3 -1
- package/dist/agent/kernel-builder.js +4 -1
- package/dist/agent/kernel-builder.js.map +1 -1
- package/dist/agent/kernel.d.ts +20 -1
- package/dist/agent/kernel.js +255 -14
- package/dist/agent/kernel.js.map +1 -1
- package/dist/agent/memory/schema.d.ts +1 -1
- package/dist/agent/memory/schema.js +9 -1
- package/dist/agent/memory/schema.js.map +1 -1
- package/dist/agent/merchant/action-candidate.d.ts +18 -0
- package/dist/agent/merchant/action-candidate.js +51 -0
- package/dist/agent/merchant/action-candidate.js.map +1 -1
- package/dist/agent/merchant/fake-merchant-client.js +6 -1
- package/dist/agent/merchant/fake-merchant-client.js.map +1 -1
- package/dist/agent/merchant/intelligence/backend.d.ts +40 -0
- package/dist/agent/merchant/intelligence/backend.js +2 -0
- package/dist/agent/merchant/intelligence/backend.js.map +1 -0
- package/dist/agent/merchant/intelligence/default-backend.d.ts +38 -0
- package/dist/agent/merchant/intelligence/default-backend.js +477 -0
- package/dist/agent/merchant/intelligence/default-backend.js.map +1 -0
- package/dist/agent/merchant/intelligence/http-analytics-source.d.ts +55 -0
- package/dist/agent/merchant/intelligence/http-analytics-source.js +193 -0
- package/dist/agent/merchant/intelligence/http-analytics-source.js.map +1 -0
- package/dist/agent/merchant/intelligence/types.d.ts +109 -0
- package/dist/agent/merchant/intelligence/types.js +2 -0
- package/dist/agent/merchant/intelligence/types.js.map +1 -0
- package/dist/agent/merchant/merchant-client.d.ts +50 -1
- package/dist/agent/merchant/merchant-client.js +157 -8
- package/dist/agent/merchant/merchant-client.js.map +1 -1
- package/dist/agent/merchant/merchant-enrichment.d.ts +10 -0
- package/dist/agent/merchant/merchant-enrichment.js +38 -0
- package/dist/agent/merchant/merchant-enrichment.js.map +1 -0
- package/dist/agent/merchant/merchant-grounding.d.ts +5 -0
- package/dist/agent/merchant/merchant-grounding.js +76 -0
- package/dist/agent/merchant/merchant-grounding.js.map +1 -0
- package/dist/agent/merchant/merchant-presentations.d.ts +8 -0
- package/dist/agent/merchant/merchant-presentations.js +207 -0
- package/dist/agent/merchant/merchant-presentations.js.map +1 -0
- package/dist/agent/merchant/merchant-tools.d.ts +8 -0
- package/dist/agent/merchant/merchant-tools.js +291 -178
- package/dist/agent/merchant/merchant-tools.js.map +1 -1
- package/dist/agent/merchant/types.d.ts +6 -2
- package/dist/agent/merchant/types.js +45 -0
- package/dist/agent/merchant/types.js.map +1 -1
- package/dist/agent/presentation/registry.d.ts +14 -0
- package/dist/agent/presentation/registry.js +24 -0
- package/dist/agent/presentation/registry.js.map +1 -0
- package/dist/agent/presentation/runner.d.ts +11 -0
- package/dist/agent/presentation/runner.js +17 -0
- package/dist/agent/presentation/runner.js.map +1 -0
- package/dist/agent/presentation/sanitize.d.ts +16 -0
- package/dist/agent/presentation/sanitize.js +37 -0
- package/dist/agent/presentation/sanitize.js.map +1 -0
- package/dist/agent/presentation/types.d.ts +28 -0
- package/dist/agent/presentation/types.js +8 -0
- package/dist/agent/presentation/types.js.map +1 -0
- package/dist/agent/session.d.ts +1 -1
- package/dist/agent/session.js +2 -2
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/skills/registry.d.ts +11 -0
- package/dist/agent/skills/registry.js +119 -0
- package/dist/agent/skills/registry.js.map +1 -0
- package/dist/agent/skills/tools.d.ts +6 -0
- package/dist/agent/skills/tools.js +36 -0
- package/dist/agent/skills/tools.js.map +1 -0
- package/dist/agent/skills/types.d.ts +9 -0
- package/dist/agent/skills/types.js +2 -0
- package/dist/agent/skills/types.js.map +1 -0
- package/dist/agent/supplier/scheduler.d.ts +2 -0
- package/dist/agent/supplier/scheduler.js +101 -22
- package/dist/agent/supplier/scheduler.js.map +1 -1
- package/dist/agent/supplier/store.d.ts +2 -0
- package/dist/agent/supplier/store.js +44 -0
- package/dist/agent/supplier/store.js.map +1 -1
- package/dist/agent/system-prompt.d.ts +5 -1
- package/dist/agent/system-prompt.js +20 -3
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/auth/merchant-authorization.d.ts +49 -0
- package/dist/auth/merchant-authorization.js +61 -0
- package/dist/auth/merchant-authorization.js.map +1 -0
- package/dist/auth/merchant-oauth.d.ts +255 -0
- package/dist/auth/merchant-oauth.js +764 -0
- package/dist/auth/merchant-oauth.js.map +1 -0
- package/dist/auth/merchant-pairing.d.ts +62 -0
- package/dist/auth/merchant-pairing.js +199 -0
- package/dist/auth/merchant-pairing.js.map +1 -0
- package/dist/auth/merchant-sessions.d.ts +71 -0
- package/dist/auth/merchant-sessions.js +168 -0
- package/dist/auth/merchant-sessions.js.map +1 -0
- package/dist/buyer-core/build-service.d.ts +5 -0
- package/dist/buyer-core/build-service.js +12 -0
- package/dist/buyer-core/build-service.js.map +1 -1
- package/dist/buyer-core/errors.d.ts +1 -1
- package/dist/buyer-core/errors.js +2 -0
- package/dist/buyer-core/errors.js.map +1 -1
- package/dist/buyer-core/merchant-index.d.ts +19 -4
- package/dist/buyer-core/merchant-index.js +137 -16
- package/dist/buyer-core/merchant-index.js.map +1 -1
- package/dist/buyer-core/negotiator.d.ts +0 -10
- package/dist/buyer-core/negotiator.js +12 -1
- package/dist/buyer-core/negotiator.js.map +1 -1
- package/dist/buyer-core/quote-fetcher.js +2 -1
- package/dist/buyer-core/quote-fetcher.js.map +1 -1
- package/dist/buyer-core/service.d.ts +104 -0
- package/dist/buyer-core/service.js +105 -1
- package/dist/buyer-core/service.js.map +1 -1
- package/dist/cli.d.ts +4 -2
- package/dist/cli.js +644 -32
- package/dist/cli.js.map +1 -1
- package/dist/config/profile.d.ts +51 -0
- package/dist/config/profile.js +185 -61
- package/dist/config/profile.js.map +1 -1
- package/dist/demo/demo-runner.js +12 -9
- package/dist/demo/demo-runner.js.map +1 -1
- package/dist/discovery/catalog-source/buyer-follows.d.ts +82 -0
- package/dist/discovery/catalog-source/buyer-follows.js +228 -0
- package/dist/discovery/catalog-source/buyer-follows.js.map +1 -0
- package/dist/discovery/catalog-source/connector-identity.d.ts +75 -0
- package/dist/discovery/catalog-source/connector-identity.js +175 -0
- package/dist/discovery/catalog-source/connector-identity.js.map +1 -0
- package/dist/discovery/catalog-source/errors.d.ts +1 -1
- package/dist/discovery/catalog-source/errors.js +2 -0
- package/dist/discovery/catalog-source/errors.js.map +1 -1
- package/dist/discovery/catalog-source/kiwi-record.d.ts +2 -0
- package/dist/discovery/catalog-source/kiwi-record.js.map +1 -1
- package/dist/discovery/catalog-source/kiwi-source.js +2 -0
- package/dist/discovery/catalog-source/kiwi-source.js.map +1 -1
- package/dist/discovery/catalog-source/merchant-publications.d.ts +65 -0
- package/dist/discovery/catalog-source/merchant-publications.js +207 -0
- package/dist/discovery/catalog-source/merchant-publications.js.map +1 -0
- package/dist/discovery/catalog-source/register.d.ts +24 -0
- package/dist/discovery/catalog-source/register.js +46 -0
- package/dist/discovery/catalog-source/register.js.map +1 -1
- package/dist/discovery/catalog-source/source.js +2 -1
- package/dist/discovery/catalog-source/source.js.map +1 -1
- package/dist/fs/atomic-write.d.ts +18 -0
- package/dist/fs/atomic-write.js +29 -0
- package/dist/fs/atomic-write.js.map +1 -0
- package/dist/handoff/authorization.js +1 -1
- package/dist/http/merchant-server.d.ts +65 -0
- package/dist/http/merchant-server.js +346 -0
- package/dist/http/merchant-server.js.map +1 -0
- package/dist/http/server.js +4 -1
- package/dist/http/server.js.map +1 -1
- package/dist/mcp/cli.d.ts +2 -0
- package/dist/mcp/cli.js +7 -6
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/merchant-auth.d.ts +78 -0
- package/dist/mcp/merchant-auth.js +146 -0
- package/dist/mcp/merchant-auth.js.map +1 -0
- package/dist/mcp/merchant-dirs.d.ts +26 -0
- package/dist/mcp/merchant-dirs.js +44 -0
- package/dist/mcp/merchant-dirs.js.map +1 -0
- package/dist/mcp/merchant-resources.d.ts +38 -0
- package/dist/mcp/merchant-resources.js +146 -0
- package/dist/mcp/merchant-resources.js.map +1 -0
- package/dist/mcp/merchant-server.d.ts +106 -0
- package/dist/mcp/merchant-server.js +615 -0
- package/dist/mcp/merchant-server.js.map +1 -0
- package/dist/mcp/merchant-tools.d.ts +103 -0
- package/dist/mcp/merchant-tools.js +517 -0
- package/dist/mcp/merchant-tools.js.map +1 -0
- package/dist/mcp/server.js +4 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +5 -3
- package/dist/mcp/tools.js +102 -5
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts +1 -1
- package/dist/mcp/types.js +4 -0
- package/dist/mcp/types.js.map +1 -1
- package/dist/merchant/ops.d.ts +0 -11
- package/dist/merchant/ops.js +13 -1
- package/dist/merchant/ops.js.map +1 -1
- package/dist/merchant/stats-store.d.ts +7 -0
- package/dist/merchant/stats-store.js +11 -0
- package/dist/merchant/stats-store.js.map +1 -1
- package/dist/merchant/workbench-service.d.ts +189 -0
- package/dist/merchant/workbench-service.js +417 -0
- package/dist/merchant/workbench-service.js.map +1 -0
- package/dist/merchant-admin/pending-page.d.ts +35 -0
- package/dist/merchant-admin/pending-page.js +69 -0
- package/dist/merchant-admin/pending-page.js.map +1 -0
- package/dist/merchant-core/commands.d.ts +99 -0
- package/dist/merchant-core/commands.js +179 -0
- package/dist/merchant-core/commands.js.map +1 -0
- package/dist/merchant-core/executor.d.ts +69 -0
- package/dist/merchant-core/executor.js +218 -0
- package/dist/merchant-core/executor.js.map +1 -0
- package/dist/merchant-core/negotiation-adapters.d.ts +55 -0
- package/dist/merchant-core/negotiation-adapters.js +55 -0
- package/dist/merchant-core/negotiation-adapters.js.map +1 -0
- package/dist/merchant-core/network-checks.d.ts +65 -0
- package/dist/merchant-core/network-checks.js +111 -0
- package/dist/merchant-core/network-checks.js.map +1 -0
- package/dist/merchant-core/operations.d.ts +64 -0
- package/dist/merchant-core/operations.js +136 -0
- package/dist/merchant-core/operations.js.map +1 -0
- package/dist/merchant-core/policy-runtime.d.ts +70 -0
- package/dist/merchant-core/policy-runtime.js +181 -0
- package/dist/merchant-core/policy-runtime.js.map +1 -0
- package/dist/merchant-core/product-import.d.ts +67 -0
- package/dist/merchant-core/product-import.js +160 -0
- package/dist/merchant-core/product-import.js.map +1 -0
- package/dist/merchant-core/service.d.ts +203 -0
- package/dist/merchant-core/service.js +402 -0
- package/dist/merchant-core/service.js.map +1 -0
- package/dist/merchant-gateway/catalog-publications.d.ts +71 -0
- package/dist/merchant-gateway/catalog-publications.js +175 -0
- package/dist/merchant-gateway/catalog-publications.js.map +1 -0
- package/dist/merchant-gateway/catalog-tools.d.ts +46 -0
- package/dist/merchant-gateway/catalog-tools.js +277 -0
- package/dist/merchant-gateway/catalog-tools.js.map +1 -0
- package/dist/merchant-gateway/cli.d.ts +75 -0
- package/dist/merchant-gateway/cli.js +458 -0
- package/dist/merchant-gateway/cli.js.map +1 -0
- package/dist/merchant-gateway/credential-vault.d.ts +44 -0
- package/dist/merchant-gateway/credential-vault.js +111 -0
- package/dist/merchant-gateway/credential-vault.js.map +1 -0
- package/dist/merchant-gateway/entry-server.d.ts +117 -0
- package/dist/merchant-gateway/entry-server.js +710 -0
- package/dist/merchant-gateway/entry-server.js.map +1 -0
- package/dist/merchant-gateway/instance-registration.d.ts +143 -0
- package/dist/merchant-gateway/instance-registration.js +382 -0
- package/dist/merchant-gateway/instance-registration.js.map +1 -0
- package/dist/merchant-gateway/instance-tools.d.ts +58 -0
- package/dist/merchant-gateway/instance-tools.js +184 -0
- package/dist/merchant-gateway/instance-tools.js.map +1 -0
- package/dist/merchant-gateway/mcp-proxy.d.ts +25 -0
- package/dist/merchant-gateway/mcp-proxy.js +192 -0
- package/dist/merchant-gateway/mcp-proxy.js.map +1 -0
- package/dist/merchant-gateway/pinned-fetch.d.ts +52 -0
- package/dist/merchant-gateway/pinned-fetch.js +212 -0
- package/dist/merchant-gateway/pinned-fetch.js.map +1 -0
- package/dist/merchant-gateway/tenant-registry.d.ts +82 -0
- package/dist/merchant-gateway/tenant-registry.js +190 -0
- package/dist/merchant-gateway/tenant-registry.js.map +1 -0
- package/dist/merchant-gateway/tool-bundle.d.ts +26 -0
- package/dist/merchant-gateway/tool-bundle.js +56 -0
- package/dist/merchant-gateway/tool-bundle.js.map +1 -0
- package/dist/merchant-runtime/backup.d.ts +48 -0
- package/dist/merchant-runtime/backup.js +226 -0
- package/dist/merchant-runtime/backup.js.map +1 -0
- package/dist/merchant-runtime/health.d.ts +99 -0
- package/dist/merchant-runtime/health.js +206 -0
- package/dist/merchant-runtime/health.js.map +1 -0
- package/dist/merchant-runtime/jobs.d.ts +64 -0
- package/dist/merchant-runtime/jobs.js +107 -0
- package/dist/merchant-runtime/jobs.js.map +1 -0
- package/dist/merchant-runtime/manager.d.ts +94 -0
- package/dist/merchant-runtime/manager.js +305 -0
- package/dist/merchant-runtime/manager.js.map +1 -0
- package/dist/merchant-runtime/services.d.ts +30 -0
- package/dist/merchant-runtime/services.js +51 -0
- package/dist/merchant-runtime/services.js.map +1 -0
- package/dist/negotiation/action-candidate.js +1 -1
- package/dist/net/url.d.ts +26 -0
- package/dist/net/url.js +32 -0
- package/dist/net/url.js.map +1 -0
- package/dist/operator/types.d.ts +1 -1
- package/dist/product-cli.d.ts +2 -2
- package/dist/product-cli.js +27 -6
- package/dist/product-cli.js.map +1 -1
- package/dist/product-compat.d.ts +9 -1
- package/dist/product-compat.js +12 -1
- package/dist/product-compat.js.map +1 -1
- package/dist/product-init.js +17 -5
- package/dist/product-init.js.map +1 -1
- package/dist/product-publish.js +2 -1
- package/dist/product-publish.js.map +1 -1
- package/dist/product-supplier.d.ts +73 -0
- package/dist/product-supplier.js +224 -5
- package/dist/product-supplier.js.map +1 -1
- package/dist/runtime/fake-model.d.ts +1 -1
- package/dist/trust/identity/jwk.d.ts +11 -0
- package/dist/trust/identity/jwk.js +2 -0
- package/dist/trust/identity/jwk.js.map +1 -0
- package/dist/trust/identity/jws.d.ts +2 -1
- package/dist/trust/identity/jws.js.map +1 -1
- package/dist/trust/identity/keys.d.ts +2 -1
- package/dist/trust/identity/keys.js.map +1 -1
- package/dist/trust/identity/message-signature.d.ts +1 -14
- package/dist/trust/identity/message-signature.js.map +1 -1
- package/dist/weixin/channel.d.ts +3 -0
- package/dist/weixin/channel.js +18 -2
- package/dist/weixin/channel.js.map +1 -1
- package/examples/profiles/merchant.deepseek.yaml +6 -0
- package/examples/profiles/merchant.fake.yaml +6 -0
- package/examples/profiles/merchant.local.yaml +6 -0
- package/package.json +9 -7
- package/skills/kiwi-buyer/SKILL.md +68 -0
- package/skills/merchant/catalog-operations/SKILL.md +17 -0
- package/skills/merchant/change-approval/SKILL.md +16 -0
- package/skills/merchant/human-review/SKILL.md +17 -0
- package/skills/merchant/inventory-operations/SKILL.md +17 -0
- package/skills/merchant/negotiation-review/SKILL.md +18 -0
- package/skills/merchant/performance-insights/SKILL.md +19 -0
- package/contracts/candidate-agent-dto-1.0.README.md +0 -43
- package/contracts/conformance/python-service/README.md +0 -19
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 第 1 版实例工具:把已配对商家实例的 `kiwi_merchant_*` 工具暴露给该商家。
|
|
18
|
+
*
|
|
19
|
+
* 路由与隔离:
|
|
20
|
+
* - 工具列表**从实例现取**(`tools/list` 经 mcp-proxy 转发并按 scope 过滤),
|
|
21
|
+
* 网关不硬编码工具清单,避免与实例版本漂移;
|
|
22
|
+
* - 调用经 `proxyTenantMcp` 转发,租户仍由已验证 token 的 `merchant_id` 决定;
|
|
23
|
+
* - 未配对实例、内部凭据缺失或实例不可用时,第 1 版工具**不出现/明确报错**,
|
|
24
|
+
* 第 0 版目录能力不受影响(发布计划 §4 第 1 条)。
|
|
25
|
+
*
|
|
26
|
+
* 缓存的只是工具清单(按商家 60 秒),不含任何业务数据;凭据从不进入缓存。
|
|
27
|
+
*/
|
|
28
|
+
import type { MerchantAuthorization } from "../auth/merchant-authorization.js";
|
|
29
|
+
import type { ScopedMcpTools } from "../mcp/merchant-server.js";
|
|
30
|
+
import type { MerchantMcpCallResult, MerchantMcpToolDefinition } from "../mcp/merchant-tools.js";
|
|
31
|
+
import { TenantBackendRegistry } from "./tenant-registry.js";
|
|
32
|
+
/** 工具清单缓存(每商家一条;TTL 内复用,避免每次 tools/list 都打实例)。 */
|
|
33
|
+
export declare class InstanceToolListCache {
|
|
34
|
+
private readonly ttlMs;
|
|
35
|
+
private readonly entries;
|
|
36
|
+
constructor(ttlMs?: number);
|
|
37
|
+
get(merchantId: string, nowMs: number): MerchantMcpToolDefinition[] | undefined;
|
|
38
|
+
set(merchantId: string, tools: MerchantMcpToolDefinition[], nowMs: number): void;
|
|
39
|
+
clear(): void;
|
|
40
|
+
}
|
|
41
|
+
export interface InstanceToolDeps {
|
|
42
|
+
registry: TenantBackendRegistry;
|
|
43
|
+
authorization: MerchantAuthorization;
|
|
44
|
+
fetchImpl?: typeof fetch;
|
|
45
|
+
cache?: InstanceToolListCache;
|
|
46
|
+
now?: () => number;
|
|
47
|
+
}
|
|
48
|
+
/** 解析实例返回的 tools/list 结果(形状不符的条目直接丢弃,不编造工具)。 */
|
|
49
|
+
export declare function parseToolList(payload: unknown): MerchantMcpToolDefinition[];
|
|
50
|
+
/** 解析实例返回的 tools/call 结果 → 网关的调用结果形状。 */
|
|
51
|
+
export declare function parseCallResult(payload: unknown): MerchantMcpCallResult;
|
|
52
|
+
/**
|
|
53
|
+
* 构建绑定到该商家实例的工具束。
|
|
54
|
+
*
|
|
55
|
+
* 未配对实例(注册表无该 merchant_id)或内部凭据不可用时返回 `undefined`:
|
|
56
|
+
* 第 1 版工具对调用方**不可见**,第 0 版目录工具与目录发布继续可用。
|
|
57
|
+
*/
|
|
58
|
+
export declare function buildInstanceTools(deps: InstanceToolDeps): ScopedMcpTools | undefined;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { proxyTenantMcp } from "./mcp-proxy.js";
|
|
17
|
+
import { createPinnedFetch } from "./pinned-fetch.js";
|
|
18
|
+
import { TenantBackendError, TenantBackendRegistry } from "./tenant-registry.js";
|
|
19
|
+
const DEFAULT_TOOL_CACHE_TTL_MS = 60_000;
|
|
20
|
+
/** 工具清单缓存(每商家一条;TTL 内复用,避免每次 tools/list 都打实例)。 */
|
|
21
|
+
export class InstanceToolListCache {
|
|
22
|
+
ttlMs;
|
|
23
|
+
entries = new Map();
|
|
24
|
+
constructor(ttlMs = DEFAULT_TOOL_CACHE_TTL_MS) {
|
|
25
|
+
this.ttlMs = ttlMs;
|
|
26
|
+
}
|
|
27
|
+
get(merchantId, nowMs) {
|
|
28
|
+
const entry = this.entries.get(merchantId);
|
|
29
|
+
if (entry === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (entry.expiresAt <= nowMs) {
|
|
32
|
+
this.entries.delete(merchantId);
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
return entry.tools;
|
|
36
|
+
}
|
|
37
|
+
set(merchantId, tools, nowMs) {
|
|
38
|
+
this.entries.set(merchantId, { tools, expiresAt: nowMs + this.ttlMs });
|
|
39
|
+
}
|
|
40
|
+
clear() {
|
|
41
|
+
this.entries.clear();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function fail(message) {
|
|
45
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
46
|
+
}
|
|
47
|
+
/** 解析实例返回的 tools/list 结果(形状不符的条目直接丢弃,不编造工具)。 */
|
|
48
|
+
export function parseToolList(payload) {
|
|
49
|
+
if (payload === null || typeof payload !== "object")
|
|
50
|
+
return [];
|
|
51
|
+
const result = payload.result;
|
|
52
|
+
if (result === null || typeof result !== "object")
|
|
53
|
+
return [];
|
|
54
|
+
const tools = result.tools;
|
|
55
|
+
if (!Array.isArray(tools))
|
|
56
|
+
return [];
|
|
57
|
+
const parsed = [];
|
|
58
|
+
for (const element of tools) {
|
|
59
|
+
if (element === null || typeof element !== "object")
|
|
60
|
+
continue;
|
|
61
|
+
const record = element;
|
|
62
|
+
const name = typeof record.name === "string" ? record.name : "";
|
|
63
|
+
if (name === "")
|
|
64
|
+
continue;
|
|
65
|
+
parsed.push({
|
|
66
|
+
name,
|
|
67
|
+
description: typeof record.description === "string" ? record.description : "",
|
|
68
|
+
inputSchema: record.inputSchema !== null && typeof record.inputSchema === "object"
|
|
69
|
+
? record.inputSchema
|
|
70
|
+
: { type: "object", properties: {} },
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return parsed;
|
|
74
|
+
}
|
|
75
|
+
/** 解析实例返回的 tools/call 结果 → 网关的调用结果形状。 */
|
|
76
|
+
export function parseCallResult(payload) {
|
|
77
|
+
if (payload === null || typeof payload !== "object") {
|
|
78
|
+
return fail("商家实例返回了无法解析的结果");
|
|
79
|
+
}
|
|
80
|
+
const record = payload;
|
|
81
|
+
if (record.error !== undefined && record.error !== null) {
|
|
82
|
+
const message = typeof record.error === "object" && record.error !== null
|
|
83
|
+
? String(record.error.message ?? "未知错误")
|
|
84
|
+
: String(record.error);
|
|
85
|
+
return fail(`商家实例返回错误:${message}`);
|
|
86
|
+
}
|
|
87
|
+
const result = record.result;
|
|
88
|
+
if (result === null || typeof result !== "object") {
|
|
89
|
+
return fail("商家实例未返回工具结果");
|
|
90
|
+
}
|
|
91
|
+
const content = result.content;
|
|
92
|
+
const textItems = [];
|
|
93
|
+
if (Array.isArray(content)) {
|
|
94
|
+
for (const item of content) {
|
|
95
|
+
if (item === null || typeof item !== "object")
|
|
96
|
+
continue;
|
|
97
|
+
const entry = item;
|
|
98
|
+
if (entry.type === "text" && typeof entry.text === "string") {
|
|
99
|
+
textItems.push({ type: "text", text: entry.text });
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
textItems.push({ type: "text", text: JSON.stringify(entry) });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const isError = result.isError === true;
|
|
107
|
+
const outcome = {
|
|
108
|
+
content: textItems.length > 0 ? textItems : [{ type: "text", text: "{}" }],
|
|
109
|
+
...(isError ? { isError: true } : {}),
|
|
110
|
+
};
|
|
111
|
+
return outcome;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 构建绑定到该商家实例的工具束。
|
|
115
|
+
*
|
|
116
|
+
* 未配对实例(注册表无该 merchant_id)或内部凭据不可用时返回 `undefined`:
|
|
117
|
+
* 第 1 版工具对调用方**不可见**,第 0 版目录工具与目录发布继续可用。
|
|
118
|
+
*/
|
|
119
|
+
export function buildInstanceTools(deps) {
|
|
120
|
+
try {
|
|
121
|
+
deps.registry.resolve(deps.authorization);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
if (err instanceof TenantBackendError)
|
|
125
|
+
return undefined;
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
const merchantId = deps.authorization.merchant_id;
|
|
129
|
+
const cache = deps.cache ?? new InstanceToolListCache();
|
|
130
|
+
const now = deps.now ?? (() => Date.now());
|
|
131
|
+
const rpc = async (method, params) => {
|
|
132
|
+
const response = await proxyTenantMcp({
|
|
133
|
+
method: "POST",
|
|
134
|
+
authorization: deps.authorization,
|
|
135
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
|
|
136
|
+
}, deps.registry,
|
|
137
|
+
// 商家实例是外部不可信端点:默认钉住已校验 IP(防 DNS 重绑定)。
|
|
138
|
+
deps.fetchImpl ?? createPinnedFetch());
|
|
139
|
+
let payload;
|
|
140
|
+
try {
|
|
141
|
+
payload = JSON.parse(response.body);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return { ok: false, message: "商家实例返回了无法解析的响应" };
|
|
145
|
+
}
|
|
146
|
+
if (response.status >= 400) {
|
|
147
|
+
const code = payload !== null &&
|
|
148
|
+
typeof payload === "object" &&
|
|
149
|
+
typeof payload.error === "string"
|
|
150
|
+
? String(payload.error)
|
|
151
|
+
: `HTTP ${response.status}`;
|
|
152
|
+
return { ok: false, message: `商家实例暂不可用(${code})` };
|
|
153
|
+
}
|
|
154
|
+
return { ok: true, payload };
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
listTools: async (_scopes) => {
|
|
158
|
+
// 工具清单由实例现取,mcp-proxy 已按**令牌 scope** 过滤(与 tools/call
|
|
159
|
+
// 同一道门禁)并按工具名 allowlist 收敛;这里不再二次过滤,避免两处
|
|
160
|
+
// 规则漂移。缓存的是该令牌视角下的清单,TTL 60 秒。
|
|
161
|
+
const cached = cache.get(merchantId, now());
|
|
162
|
+
if (cached !== undefined)
|
|
163
|
+
return cached;
|
|
164
|
+
const result = await rpc("tools/list", {});
|
|
165
|
+
if (!result.ok)
|
|
166
|
+
return []; // 实例不可达:第 1 版工具不可见,第 0 版照常
|
|
167
|
+
const tools = parseToolList(result.payload);
|
|
168
|
+
if (tools.length > 0)
|
|
169
|
+
cache.set(merchantId, tools, now());
|
|
170
|
+
return tools;
|
|
171
|
+
},
|
|
172
|
+
call: async (name, args, _scopes) => {
|
|
173
|
+
const cached = cache.get(merchantId, now());
|
|
174
|
+
if (cached !== undefined && !cached.some((tool) => tool.name === name)) {
|
|
175
|
+
return fail(`商家实例未提供工具 ${name}(或当前授权不含所需 scope)`);
|
|
176
|
+
}
|
|
177
|
+
const result = await rpc("tools/call", { name, arguments: args });
|
|
178
|
+
if (!result.ok)
|
|
179
|
+
return fail(result.message);
|
|
180
|
+
return parseCallResult(result.payload);
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=instance-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-tools.js","sourceRoot":"","sources":["../../src/merchant-gateway/instance-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 通用 Merchant MCP Gateway 的已认证请求分发层。
|
|
3
|
+
*
|
|
4
|
+
* 后端 URL 来自服务端 TenantBackendRegistry;模型参数无法更换租户。
|
|
5
|
+
* 这只是网关的一层,不负责 WorkBuddy OAuth 登录、服务托管或公网监听。
|
|
6
|
+
*/
|
|
7
|
+
import type { MerchantAuthorization } from "../auth/merchant-authorization.js";
|
|
8
|
+
import { TenantBackendRegistry } from "./tenant-registry.js";
|
|
9
|
+
export interface McpGatewayRequest {
|
|
10
|
+
method: "POST" | "GET";
|
|
11
|
+
body?: string;
|
|
12
|
+
accept?: string;
|
|
13
|
+
protocolVersion?: string;
|
|
14
|
+
authorization: MerchantAuthorization;
|
|
15
|
+
}
|
|
16
|
+
export interface McpGatewayResponse {
|
|
17
|
+
status: number;
|
|
18
|
+
contentType: string;
|
|
19
|
+
body: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 代理一个 MCP 请求。只支持 stateless JSON 响应;SSE/重定向 fail-closed。
|
|
23
|
+
* WorkBuddy 真实联调前须验证它与客户端的 Accept/transport 协商一致。
|
|
24
|
+
*/
|
|
25
|
+
export declare function proxyTenantMcp(request: McpGatewayRequest, registry: TenantBackendRegistry, fetchImpl?: typeof fetch): Promise<McpGatewayResponse>;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 通用 Merchant MCP Gateway 的已认证请求分发层。
|
|
3
|
+
*
|
|
4
|
+
* 后端 URL 来自服务端 TenantBackendRegistry;模型参数无法更换租户。
|
|
5
|
+
* 这只是网关的一层,不负责 WorkBuddy OAuth 登录、服务托管或公网监听。
|
|
6
|
+
*/
|
|
7
|
+
import { requiredScopeForTool } from "../mcp/merchant-tools.js";
|
|
8
|
+
import { TenantBackendError, TenantBackendRegistry } from "./tenant-registry.js";
|
|
9
|
+
const MAX_REQUEST_BYTES = 1_048_576;
|
|
10
|
+
const MAX_RESPONSE_BYTES = 1_048_576;
|
|
11
|
+
const ALLOWED_TOOLS = new Set([
|
|
12
|
+
"kiwi_merchant_list_products",
|
|
13
|
+
"kiwi_merchant_get_product",
|
|
14
|
+
"kiwi_merchant_get_inventory",
|
|
15
|
+
"kiwi_merchant_list_a2a_negotiations",
|
|
16
|
+
"kiwi_merchant_list_human_reviews",
|
|
17
|
+
"kiwi_merchant_get_analytics",
|
|
18
|
+
"kiwi_merchant_prepare_product_change",
|
|
19
|
+
"kiwi_merchant_prepare_product_create",
|
|
20
|
+
"kiwi_merchant_prepare_inventory_update",
|
|
21
|
+
"kiwi_merchant_prepare_listing_change",
|
|
22
|
+
"kiwi_merchant_prepare_review_resolve",
|
|
23
|
+
"kiwi_merchant_prepare_policy_change",
|
|
24
|
+
"kiwi_merchant_prepare_products_import",
|
|
25
|
+
"kiwi_merchant_prepare_products_withdraw",
|
|
26
|
+
"kiwi_merchant_get_operation",
|
|
27
|
+
]);
|
|
28
|
+
function json(status, body) {
|
|
29
|
+
return { status, contentType: "application/json", body: JSON.stringify(body) };
|
|
30
|
+
}
|
|
31
|
+
function scopeAllowed(authorization, scope) {
|
|
32
|
+
return authorization.scopes.includes(scope);
|
|
33
|
+
}
|
|
34
|
+
function gateRpc(body, authorization) {
|
|
35
|
+
let rpc;
|
|
36
|
+
try {
|
|
37
|
+
rpc = JSON.parse(body);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return json(400, { error: "invalid_json", message: "MCP JSON-RPC 请求无效" });
|
|
41
|
+
}
|
|
42
|
+
if (rpc === null || typeof rpc !== "object" || Array.isArray(rpc)) {
|
|
43
|
+
return json(400, { error: "invalid_request", message: "MCP JSON-RPC 请求无效" });
|
|
44
|
+
}
|
|
45
|
+
const request = rpc;
|
|
46
|
+
if (request.jsonrpc !== "2.0" || typeof request.method !== "string") {
|
|
47
|
+
return json(400, { error: "invalid_request", message: "MCP JSON-RPC 请求无效" });
|
|
48
|
+
}
|
|
49
|
+
const method = request.method;
|
|
50
|
+
if (["initialize", "notifications/initialized", "ping"].includes(method))
|
|
51
|
+
return undefined;
|
|
52
|
+
if (["tools/list", "resources/list", "resources/read"].includes(method)) {
|
|
53
|
+
if (!scopeAllowed(authorization, "merchant:read")) {
|
|
54
|
+
return json(403, { error: "insufficient_scope", required_scope: "merchant:read" });
|
|
55
|
+
}
|
|
56
|
+
if (method === "resources/read") {
|
|
57
|
+
const params = request.params;
|
|
58
|
+
if (typeof params?.uri !== "string" ||
|
|
59
|
+
!/^kiwi-merchant:\/\/presentation\/[a-z_]+$/.test(params.uri)) {
|
|
60
|
+
return json(403, { error: "resource_not_allowed" });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
if (method === "tools/call") {
|
|
66
|
+
const params = request.params;
|
|
67
|
+
if (typeof params?.name !== "string" || !ALLOWED_TOOLS.has(params.name)) {
|
|
68
|
+
return json(403, { error: "tool_not_allowed" });
|
|
69
|
+
}
|
|
70
|
+
const required = requiredScopeForTool(params.name);
|
|
71
|
+
if (!scopeAllowed(authorization, required)) {
|
|
72
|
+
return json(403, { error: "insufficient_scope", required_scope: required });
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
return json(403, { error: "method_not_allowed" });
|
|
77
|
+
}
|
|
78
|
+
async function readBoundedResponse(response) {
|
|
79
|
+
if (response.body === null)
|
|
80
|
+
return "";
|
|
81
|
+
const reader = response.body.getReader();
|
|
82
|
+
const chunks = [];
|
|
83
|
+
let length = 0;
|
|
84
|
+
try {
|
|
85
|
+
while (true) {
|
|
86
|
+
const next = await reader.read();
|
|
87
|
+
if (next.done)
|
|
88
|
+
break;
|
|
89
|
+
length += next.value.byteLength;
|
|
90
|
+
if (length > MAX_RESPONSE_BYTES) {
|
|
91
|
+
await reader.cancel();
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
chunks.push(next.value);
|
|
95
|
+
}
|
|
96
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks));
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
reader.releaseLock();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 代理一个 MCP 请求。只支持 stateless JSON 响应;SSE/重定向 fail-closed。
|
|
104
|
+
* WorkBuddy 真实联调前须验证它与客户端的 Accept/transport 协商一致。
|
|
105
|
+
*/
|
|
106
|
+
export async function proxyTenantMcp(request, registry, fetchImpl = fetch) {
|
|
107
|
+
if (!request.authorization.merchant_id || !request.authorization.principal_id) {
|
|
108
|
+
return json(401, { error: "unauthorized" });
|
|
109
|
+
}
|
|
110
|
+
if (request.method !== "POST") {
|
|
111
|
+
return json(405, { error: "method_not_allowed" });
|
|
112
|
+
}
|
|
113
|
+
const body = request.body ?? "";
|
|
114
|
+
if (Buffer.byteLength(body, "utf8") > MAX_REQUEST_BYTES) {
|
|
115
|
+
return json(413, { error: "request_too_large" });
|
|
116
|
+
}
|
|
117
|
+
const gated = gateRpc(body, request.authorization);
|
|
118
|
+
if (gated !== undefined)
|
|
119
|
+
return gated;
|
|
120
|
+
// 只能在完成 OAuth 校验与 tool/scope gate 之后解析后端;不存在的商家没有
|
|
121
|
+
// 任何“缺省商家”回退。Backend secret 不进入返回结果或错误正文。
|
|
122
|
+
let backend;
|
|
123
|
+
try {
|
|
124
|
+
backend = registry.resolve(request.authorization);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
if (error instanceof TenantBackendError) {
|
|
128
|
+
return json(503, { error: error.code });
|
|
129
|
+
}
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
let upstream;
|
|
133
|
+
try {
|
|
134
|
+
upstream = await fetchImpl(backend.mcpUrl, {
|
|
135
|
+
method: "POST",
|
|
136
|
+
redirect: "manual",
|
|
137
|
+
headers: {
|
|
138
|
+
authorization: `Bearer ${backend.bearerToken}`,
|
|
139
|
+
accept: "application/json, text/event-stream",
|
|
140
|
+
"content-type": "application/json",
|
|
141
|
+
...(request.protocolVersion !== undefined
|
|
142
|
+
? { "mcp-protocol-version": request.protocolVersion }
|
|
143
|
+
: {}),
|
|
144
|
+
},
|
|
145
|
+
body,
|
|
146
|
+
signal: AbortSignal.timeout(30_000),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
if (process.env.KIWI_GATEWAY_DEBUG_PROXY === "1") {
|
|
151
|
+
process.stderr.write(`[gateway proxy] backend fetch failed: ${err instanceof Error ? `${err.name}: ${err.message}` : String(err)}\n`);
|
|
152
|
+
}
|
|
153
|
+
return json(502, { error: "backend_unavailable" });
|
|
154
|
+
}
|
|
155
|
+
if (upstream.status >= 300 && upstream.status < 400) {
|
|
156
|
+
return json(502, { error: "backend_redirect_rejected" });
|
|
157
|
+
}
|
|
158
|
+
const contentType = upstream.headers.get("content-type") ?? "";
|
|
159
|
+
if (!/^application\/json(?:\s*;|\s*$)/i.test(contentType)) {
|
|
160
|
+
return json(502, { error: "backend_content_type_unsupported" });
|
|
161
|
+
}
|
|
162
|
+
const contentLength = Number(upstream.headers.get("content-length") ?? "0");
|
|
163
|
+
if (contentLength > MAX_RESPONSE_BYTES)
|
|
164
|
+
return json(502, { error: "backend_response_too_large" });
|
|
165
|
+
let responseBody;
|
|
166
|
+
try {
|
|
167
|
+
responseBody = await readBoundedResponse(upstream);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return json(502, { error: "backend_response_unreadable" });
|
|
171
|
+
}
|
|
172
|
+
if (responseBody === undefined) {
|
|
173
|
+
return json(502, { error: "backend_response_too_large" });
|
|
174
|
+
}
|
|
175
|
+
if (JSON.parse(body).method === "tools/list" && upstream.ok) {
|
|
176
|
+
let payload;
|
|
177
|
+
try {
|
|
178
|
+
payload = JSON.parse(responseBody);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return json(502, { error: "backend_invalid_json" });
|
|
182
|
+
}
|
|
183
|
+
if (Array.isArray(payload.result?.tools)) {
|
|
184
|
+
payload.result.tools = payload.result.tools.filter((tool) => typeof tool.name === "string" &&
|
|
185
|
+
ALLOWED_TOOLS.has(tool.name) &&
|
|
186
|
+
scopeAllowed(request.authorization, requiredScopeForTool(tool.name)));
|
|
187
|
+
return json(upstream.status, payload);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return { status: upstream.status, contentType: "application/json", body: responseBody };
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=mcp-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-proxy.js","sourceRoot":"","sources":["../../src/merchant-gateway/mcp-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
export declare class PinnedFetchError extends Error {
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
/** 我们用到的那几个 fetch init 字段(避免依赖 DOM/undici 的类型名)。 */
|
|
20
|
+
interface FetchInit {
|
|
21
|
+
method?: string;
|
|
22
|
+
headers?: unknown;
|
|
23
|
+
body?: unknown;
|
|
24
|
+
signal?: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface PinnedFetchOptions {
|
|
27
|
+
/** 自定义解析(测试用);返回该主机名的全部 A/AAAA 记录。 */
|
|
28
|
+
resolveIp?: (hostname: string) => Promise<string[]>;
|
|
29
|
+
/** 请求超时(毫秒);缺省由调用方通过 AbortSignal 控制。 */
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 解析 + 校验 + 选定一个可直连的 IP。
|
|
34
|
+
*
|
|
35
|
+
* 与 `assertResolvableTargetUrl` 同一套规则,但把「校验用的解析结果」原样
|
|
36
|
+
* 返回给调用方去建连,消除两次解析之间的窗口。
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolvePinnedAddress(hostname: string, resolve: (hostname: string) => Promise<string[]>): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* 按**给定地址**建连(钉住的落点),HTTP 适配层:
|
|
41
|
+
* `host: <address>` + `Host: <主机名>`(https 另加 servername 供 SNI/证书校验)。
|
|
42
|
+
* 单独导出便于对本地服务做往返测试(不经过 DNS 策略)。
|
|
43
|
+
*/
|
|
44
|
+
export declare function requestViaAddress(url: URL, address: string, init?: FetchInit): Promise<Response>;
|
|
45
|
+
/**
|
|
46
|
+
* 构造一个把目标主机**钉在已校验 IP** 上的 fetch 实现。
|
|
47
|
+
*
|
|
48
|
+
* 语义与 fetch 的差异(故意为之):不跟随重定向;响应体一次性读完(JSON-RPC
|
|
49
|
+
* 体量小);不处理 cookie / 流式上传。
|
|
50
|
+
*/
|
|
51
|
+
export declare function createPinnedFetch(options?: PinnedFetchOptions): typeof fetch;
|
|
52
|
+
export {};
|