@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,458 @@
|
|
|
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
|
+
* `kiwi merchant gateway serve` —— 商家连接器(「Kiwi 商家运营」)的远程 MCP 入口。
|
|
18
|
+
*
|
|
19
|
+
* merchant-buddy 第 1 版设计 §3.2 / 商家连接器发布计划 §2:买方连接器
|
|
20
|
+
* (`kiwi-sourcing`,本地 stdio)由本命令之外的路径承载;本进程只服务商家侧,
|
|
21
|
+
* 服务端连接共享 `kiwi-catalog`,第 0 版提供公开资料能力,第 1 版按服务端
|
|
22
|
+
* 注册表路由到商家自托管实例。
|
|
23
|
+
*
|
|
24
|
+
* 部署形态(两种,均要求公网为 HTTPS):
|
|
25
|
+
*
|
|
26
|
+
* 1) 反向代理终止 TLS(推荐):本进程 `--host 127.0.0.1`(默认),
|
|
27
|
+
* `--public-url https://…` 指向代理对外地址;
|
|
28
|
+
* 2) 本进程直接终止 TLS:`--tls-cert/--tls-key`(可配合非 loopback 监听)。
|
|
29
|
+
*
|
|
30
|
+
* 监听非 loopback 且既无 TLS 材料又未显式 `--trusted-proxy` 时**拒绝启动**
|
|
31
|
+
* (fail-closed);不做“默认相信前面有代理”的推断。
|
|
32
|
+
*
|
|
33
|
+
* 凭据分工(互不通用,详见启动摘要):
|
|
34
|
+
* - **用户 OAuth token**:WorkBuddy ↔ 入口。授权码 + PKCE 签发,入口只存摘要;
|
|
35
|
+
* - **connector token**(`--connector-token-env`):入口 → 目录的机器凭据,
|
|
36
|
+
* 仅用于创建/兑换一次性身份授权请求,**不授予任何商家数据访问**;
|
|
37
|
+
* - **商家目录凭据 `cmt_…`**:入口 → 目录的商家作用域凭据(读写该商家公开
|
|
38
|
+
* 资料;发布仍须商家在门户确认);由兑换签发,加密保管;
|
|
39
|
+
* - **实例内部凭据**(第 1 版):入口 → 商家自托管 MCP 实例;同样加密保管;
|
|
40
|
+
* - **凭据加密密钥**(`--credential-key-env`):仅本进程使用,不落库、不下发。
|
|
41
|
+
*
|
|
42
|
+
* 缺少加密密钥时**不启用**依赖加密存储的功能(目录工具与实例路由),
|
|
43
|
+
* 但入口本身仍可启动(连接流程与健康检查可用)——第 0 版注册/发布不会因
|
|
44
|
+
* 尚未配对实例或缺少实例凭据而被阻塞。
|
|
45
|
+
*/
|
|
46
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
47
|
+
import path from "node:path";
|
|
48
|
+
import { DatabaseSync } from "node:sqlite";
|
|
49
|
+
import { expectedCallbackUri, MerchantOAuthServer, MerchantOAuthStore, } from "../auth/merchant-oauth.js";
|
|
50
|
+
import { MerchantAdminSessions } from "../auth/merchant-sessions.js";
|
|
51
|
+
import { MerchantOAuthVerifier } from "../auth/merchant-authorization.js";
|
|
52
|
+
import { CatalogConnectorIdentityClient } from "../discovery/catalog-source/connector-identity.js";
|
|
53
|
+
import { isLoopbackHost } from "../a2a/client/url-policy.js";
|
|
54
|
+
import { EXIT } from "../exit-codes.js";
|
|
55
|
+
import { buildCatalogTools } from "./catalog-tools.js";
|
|
56
|
+
import { MerchantPublicationClient } from "./catalog-publications.js";
|
|
57
|
+
import { GatewayCredentialVault } from "./credential-vault.js";
|
|
58
|
+
import { buildInstanceTools, InstanceToolListCache } from "./instance-tools.js";
|
|
59
|
+
import { InstanceRegistrationStore } from "./instance-registration.js";
|
|
60
|
+
import { combineScopedTools } from "./tool-bundle.js";
|
|
61
|
+
import { loadTenantBackendConfigs, TenantBackendError, TenantBackendRegistry, } from "./tenant-registry.js";
|
|
62
|
+
import { DEFAULT_GATEWAY_ENTRY_PATH, DEFAULT_GATEWAY_ENTRY_PORT, startGatewayEntryServer, } from "./entry-server.js";
|
|
63
|
+
const DEFAULT_CATALOG_URL = "https://catalog.kiwi.harrylabsj.com";
|
|
64
|
+
/** 默认商家连接器 source(平台唯一性待核验;核验后按此处替换即可)。 */
|
|
65
|
+
export const DEFAULT_MERCHANT_CONNECTOR_SOURCE = "kiwi-merchant";
|
|
66
|
+
const DEFAULT_CONNECTOR_TOKEN_ENV = "KIWI_CATALOG_CONNECTOR_TOKEN";
|
|
67
|
+
export function defaultGatewayDataDir(cwd = process.cwd()) {
|
|
68
|
+
return path.join(cwd, ".kiwi", "gateway");
|
|
69
|
+
}
|
|
70
|
+
/** 解析 `kiwi merchant gateway serve` 的原始 flag(含 `--check`)。 */
|
|
71
|
+
export function parseGatewayServeArgs(args, env = process.env) {
|
|
72
|
+
const opts = {
|
|
73
|
+
catalogUrl: env.KIWI_CATALOG_URL ?? DEFAULT_CATALOG_URL,
|
|
74
|
+
source: DEFAULT_MERCHANT_CONNECTOR_SOURCE,
|
|
75
|
+
host: "127.0.0.1",
|
|
76
|
+
port: DEFAULT_GATEWAY_ENTRY_PORT,
|
|
77
|
+
mcpPath: DEFAULT_GATEWAY_ENTRY_PATH,
|
|
78
|
+
dataDir: defaultGatewayDataDir(),
|
|
79
|
+
connectorTokenEnv: DEFAULT_CONNECTOR_TOKEN_ENV,
|
|
80
|
+
credentialKeyEnv: "KIWI_GATEWAY_CREDENTIAL_KEY",
|
|
81
|
+
trustedProxy: false,
|
|
82
|
+
allowLoopbackCallback: true,
|
|
83
|
+
checkOnly: false,
|
|
84
|
+
};
|
|
85
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
86
|
+
const flag = args[i];
|
|
87
|
+
const value = args[i + 1];
|
|
88
|
+
if (flag === "--check") {
|
|
89
|
+
opts.checkOnly = true;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (flag === "--trusted-proxy") {
|
|
93
|
+
opts.trustedProxy = true;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (flag === "--no-loopback-callback") {
|
|
97
|
+
opts.allowLoopbackCallback = false;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (value === undefined)
|
|
101
|
+
continue;
|
|
102
|
+
if (flag === "--public-url")
|
|
103
|
+
opts.publicUrl = value;
|
|
104
|
+
else if (flag === "--catalog-url")
|
|
105
|
+
opts.catalogUrl = value;
|
|
106
|
+
else if (flag === "--source")
|
|
107
|
+
opts.source = value;
|
|
108
|
+
else if (flag === "--host")
|
|
109
|
+
opts.host = value;
|
|
110
|
+
else if (flag === "--port")
|
|
111
|
+
opts.port = Number(value);
|
|
112
|
+
else if (flag === "--mcp-path")
|
|
113
|
+
opts.mcpPath = value;
|
|
114
|
+
else if (flag === "--data-dir")
|
|
115
|
+
opts.dataDir = value;
|
|
116
|
+
else if (flag === "--connector-token-env")
|
|
117
|
+
opts.connectorTokenEnv = value;
|
|
118
|
+
else if (flag === "--credential-key-env")
|
|
119
|
+
opts.credentialKeyEnv = value;
|
|
120
|
+
else if (flag === "--tls-cert")
|
|
121
|
+
opts.tlsCertPath = value;
|
|
122
|
+
else if (flag === "--tls-key")
|
|
123
|
+
opts.tlsKeyPath = value;
|
|
124
|
+
else if (flag === "--callback-uri")
|
|
125
|
+
opts.callbackUri = value;
|
|
126
|
+
else if (flag === "--portal-url")
|
|
127
|
+
opts.portalBaseUrl = value;
|
|
128
|
+
else if (flag === "--tenant-config")
|
|
129
|
+
opts.tenantConfigPath = value;
|
|
130
|
+
}
|
|
131
|
+
return opts;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 启动前校验(fail-closed)。纯函数,便于测试与 `--check` 复用。
|
|
135
|
+
*
|
|
136
|
+
* 规则:
|
|
137
|
+
* - `--public-url` 必填,且 https(loopback http 仅限本地开发);
|
|
138
|
+
* - 监听非 loopback 必须给出 TLS 材料,或显式 `--trusted-proxy`;
|
|
139
|
+
* - TLS 证书与私钥必须成对;
|
|
140
|
+
* - connector token 必须已配置(缺少则入口无法建立商家身份,直接拒绝启动);
|
|
141
|
+
* - 凭据加密密钥缺失**不**拒绝启动,但关闭依赖加密存储的功能并给出警告。
|
|
142
|
+
*/
|
|
143
|
+
export function validateGatewayServeOptions(opts, env = process.env) {
|
|
144
|
+
const publicUrlRaw = (opts.publicUrl ?? "").trim();
|
|
145
|
+
if (publicUrlRaw === "") {
|
|
146
|
+
return {
|
|
147
|
+
ok: false,
|
|
148
|
+
error: "缺少 --public-url(公网 HTTPS 入口,用于 OAuth issuer 与连接回跳)",
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
let publicUrl;
|
|
152
|
+
try {
|
|
153
|
+
publicUrl = new URL(publicUrlRaw);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return { ok: false, error: `--public-url 不是合法 URL:${publicUrlRaw}` };
|
|
157
|
+
}
|
|
158
|
+
if (publicUrl.username !== "" || publicUrl.password !== "") {
|
|
159
|
+
return { ok: false, error: "--public-url 不得内嵌凭据(userinfo)" };
|
|
160
|
+
}
|
|
161
|
+
if (publicUrl.search !== "" || publicUrl.hash !== "") {
|
|
162
|
+
return { ok: false, error: "--public-url 不得包含查询串或片段" };
|
|
163
|
+
}
|
|
164
|
+
if (publicUrl.protocol !== "https:" && !isLoopbackHost(publicUrl.hostname)) {
|
|
165
|
+
return {
|
|
166
|
+
ok: false,
|
|
167
|
+
error: `--public-url 必须是 https(除非 loopback 开发地址):${publicUrlRaw}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (!Number.isInteger(opts.port) || opts.port <= 0 || opts.port > 65535) {
|
|
171
|
+
return { ok: false, error: `--port 非法:${opts.port}` };
|
|
172
|
+
}
|
|
173
|
+
if (!/^[a-z0-9][a-z0-9-]{0,62}$/.test(opts.source)) {
|
|
174
|
+
return { ok: false, error: `--source 非法(小写字母/数字/连字符):${opts.source}` };
|
|
175
|
+
}
|
|
176
|
+
// 目录地址校验:http(s)、无 userinfo、无查询串。
|
|
177
|
+
try {
|
|
178
|
+
const catalogUrl = new URL(opts.catalogUrl);
|
|
179
|
+
if ((catalogUrl.protocol !== "http:" && catalogUrl.protocol !== "https:") ||
|
|
180
|
+
catalogUrl.username !== "" ||
|
|
181
|
+
catalogUrl.password !== "") {
|
|
182
|
+
return { ok: false, error: `--catalog-url 非法:${opts.catalogUrl}` };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return { ok: false, error: `--catalog-url 非法:${opts.catalogUrl}` };
|
|
187
|
+
}
|
|
188
|
+
const hasCert = (opts.tlsCertPath ?? "").trim() !== "";
|
|
189
|
+
const hasKey = (opts.tlsKeyPath ?? "").trim() !== "";
|
|
190
|
+
if (hasCert !== hasKey) {
|
|
191
|
+
return { ok: false, error: "--tls-cert 与 --tls-key 必须成对提供" };
|
|
192
|
+
}
|
|
193
|
+
if (hasCert) {
|
|
194
|
+
for (const file of [opts.tlsCertPath, opts.tlsKeyPath]) {
|
|
195
|
+
if (!existsSync(String(file))) {
|
|
196
|
+
return { ok: false, error: `TLS 材料不存在:${file}` };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const nonLoopback = !isLoopbackHost(opts.host);
|
|
201
|
+
if (nonLoopback && !hasCert && !opts.trustedProxy) {
|
|
202
|
+
return {
|
|
203
|
+
ok: false,
|
|
204
|
+
error: `监听非 loopback 地址(${opts.host})时必须二选一:` +
|
|
205
|
+
"提供 --tls-cert/--tls-key 由本进程终止 TLS,或显式声明 --trusted-proxy(TLS 由受信反向代理终止)",
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const connectorToken = (env[opts.connectorTokenEnv] ?? "").trim();
|
|
209
|
+
if (connectorToken === "") {
|
|
210
|
+
return {
|
|
211
|
+
ok: false,
|
|
212
|
+
error: `环境变量 ${opts.connectorTokenEnv} 未配置:入口需要目录发给的 connector token ` +
|
|
213
|
+
"才能创建/兑换一次性身份授权请求(它不授予商家数据访问)",
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const credentialKey = (env[opts.credentialKeyEnv] ?? "").trim();
|
|
217
|
+
const warnings = [];
|
|
218
|
+
if (credentialKey === "") {
|
|
219
|
+
warnings.push(`环境变量 ${opts.credentialKeyEnv} 未配置:依赖加密存储的功能(第 0 版目录工具、第 1 版实例路由)未启用。` +
|
|
220
|
+
"配置该密钥后重启即可启用(商家需重新连接一次)。");
|
|
221
|
+
}
|
|
222
|
+
let registeredInstances = 0;
|
|
223
|
+
if ((opts.tenantConfigPath ?? "").trim() !== "") {
|
|
224
|
+
const configPath = String(opts.tenantConfigPath);
|
|
225
|
+
if (!existsSync(configPath)) {
|
|
226
|
+
return { ok: false, error: `租户配置文件不存在:${configPath}` };
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const configs = loadTenantBackendConfigs(readFileSync(configPath, "utf8"));
|
|
230
|
+
registeredInstances = new TenantBackendRegistry(configs).size;
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
return {
|
|
234
|
+
ok: false,
|
|
235
|
+
error: err instanceof TenantBackendError ? err.message : String(err),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (nonLoopback && opts.trustedProxy && !hasCert) {
|
|
240
|
+
warnings.push(`监听 ${opts.host} 且未由本进程终止 TLS:仅当受信反向代理已终止 TLS 并限制直连时可用;` +
|
|
241
|
+
`公网入口必须为 ${publicUrl.origin}。`);
|
|
242
|
+
}
|
|
243
|
+
if (publicUrl.protocol === "http:") {
|
|
244
|
+
warnings.push("--public-url 为 http(loopback 开发地址):不可用于生产。");
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
ok: true,
|
|
248
|
+
readiness: {
|
|
249
|
+
publicUrl: publicUrl.origin,
|
|
250
|
+
callbackUri: expectedCallbackUri(opts.source, {
|
|
251
|
+
...(opts.callbackUri !== undefined ? { expectedCallbackUri: opts.callbackUri } : {}),
|
|
252
|
+
allowLoopbackFallback: opts.allowLoopbackCallback,
|
|
253
|
+
}),
|
|
254
|
+
directTls: hasCert,
|
|
255
|
+
nonLoopback,
|
|
256
|
+
encryptedFeaturesEnabled: credentialKey !== "",
|
|
257
|
+
registeredInstances,
|
|
258
|
+
connectorTokenConfigured: true,
|
|
259
|
+
warnings,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function resolveGatewayDataDir(dir) {
|
|
264
|
+
const resolved = path.resolve(dir);
|
|
265
|
+
mkdirSync(resolved, { recursive: true, mode: 0o700 });
|
|
266
|
+
try {
|
|
267
|
+
chmodSync(resolved, 0o700);
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
// 只读/受限文件系统:目录已按 0700 创建,权限收紧失败不阻塞启动。
|
|
271
|
+
}
|
|
272
|
+
return resolved;
|
|
273
|
+
}
|
|
274
|
+
/** 打开(或预建)oauth.sqlite:先以 0600 建空文件再打开,消除权限窗口。 */
|
|
275
|
+
function openGatewayStore(dataDir) {
|
|
276
|
+
const dbPath = path.join(dataDir, "oauth.sqlite");
|
|
277
|
+
if (!existsSync(dbPath)) {
|
|
278
|
+
writeFileSync(dbPath, "", { mode: 0o600 });
|
|
279
|
+
}
|
|
280
|
+
const db = new DatabaseSync(dbPath);
|
|
281
|
+
chmodSync(dbPath, 0o600);
|
|
282
|
+
return db;
|
|
283
|
+
}
|
|
284
|
+
const USAGE = `usage: kiwi merchant gateway serve [options]
|
|
285
|
+
|
|
286
|
+
商家连接器(Kiwi 商家运营)远程 MCP 入口。买方连接器(kiwi-sourcing)由
|
|
287
|
+
本地 stdio 承载,不由本命令提供服务。
|
|
288
|
+
|
|
289
|
+
--public-url <url> 必填。公网入口(https;loopback http 仅限开发)
|
|
290
|
+
--catalog-url <url> kiwi-catalog 地址(缺省 KIWI_CATALOG_URL)
|
|
291
|
+
--source <name> 连接器 source(缺省 ${DEFAULT_MERCHANT_CONNECTOR_SOURCE})
|
|
292
|
+
--host <host> 监听地址(缺省 127.0.0.1)
|
|
293
|
+
--port <n> 监听端口(缺省 ${DEFAULT_GATEWAY_ENTRY_PORT})
|
|
294
|
+
--mcp-path <path> MCP endpoint 路径(缺省 /mcp)
|
|
295
|
+
--data-dir <dir> 状态目录(缺省 <cwd>/.kiwi/gateway)
|
|
296
|
+
--connector-token-env <ENV> connector token 的环境变量名(缺省 ${DEFAULT_CONNECTOR_TOKEN_ENV})
|
|
297
|
+
--credential-key-env <ENV> 凭据加密密钥的环境变量名(缺省 KIWI_GATEWAY_CREDENTIAL_KEY)
|
|
298
|
+
--tls-cert <file> TLS 证书(与 --tls-key 成对;由本进程终止 TLS)
|
|
299
|
+
--tls-key <file> TLS 私钥
|
|
300
|
+
--trusted-proxy TLS 由受信反向代理终止(允许监听非 loopback)
|
|
301
|
+
--callback-uri <uri> 显式指定期望 OAuth 回调(缺省按 source 派生)
|
|
302
|
+
--no-loopback-callback 不允许 http loopback 回退回调
|
|
303
|
+
--portal-url <url> 目录门户地址(公开资料确认入口)
|
|
304
|
+
--tenant-config <file> 商家实例注册表 JSON({tenants:[{merchant_id,mcp_url,
|
|
305
|
+
token_env|credential_kind:"vault"}]};可选,商家也可在
|
|
306
|
+
/instance 页面自助绑定实例)
|
|
307
|
+
--check 只校验配置与就绪状态,不启动监听
|
|
308
|
+
`;
|
|
309
|
+
/** 启动摘要:把三类凭据的分工与功能开关显式打印,避免部署误判。 */
|
|
310
|
+
function printReadiness(opts, readiness, handle) {
|
|
311
|
+
const listen = handle === undefined ? `${opts.host}:${opts.port}(未启动)` : handle.url;
|
|
312
|
+
const lines = [
|
|
313
|
+
"kiwi merchant gateway serve",
|
|
314
|
+
` 公网入口 ${readiness.publicUrl}`,
|
|
315
|
+
` 本地监听 ${listen}${readiness.directTls ? "(本进程终止 TLS)" : "(TLS 应由受信反向代理终止)"}`,
|
|
316
|
+
` 连接器 source ${opts.source}`,
|
|
317
|
+
` OAuth 回调 ${readiness.callbackUri}`,
|
|
318
|
+
` 目录服务 ${opts.catalogUrl}`,
|
|
319
|
+
` 状态目录 ${opts.dataDir}`,
|
|
320
|
+
` 实例绑定页 ${readiness.publicUrl}/instance(需商家登录态)`,
|
|
321
|
+
"凭据分工(互不通用):",
|
|
322
|
+
" 用户 OAuth token WorkBuddy ↔ 入口(授权码 + PKCE;入口只存摘要)",
|
|
323
|
+
` connector token 入口 → 目录:创建/兑换一次性身份授权请求(env ${opts.connectorTokenEnv}),不授予商家数据访问`,
|
|
324
|
+
" 商家目录凭据 cmt_… 入口 → 目录:读写该商家公开资料(发布仍须商家在门户确认)",
|
|
325
|
+
" 实例内部凭据 入口 → 商家自托管实例(第 1 版路由)",
|
|
326
|
+
` 凭据加密密钥 仅本进程使用(env ${opts.credentialKeyEnv}),不落库、不下发`,
|
|
327
|
+
"功能:",
|
|
328
|
+
" ✓ 商家连接与授权(OAuth 2.1 + PKCE)",
|
|
329
|
+
readiness.encryptedFeaturesEnabled
|
|
330
|
+
? " ✓ 第 0 版目录工具(公开资料草稿/状态/撤回 + 门户确认入口)"
|
|
331
|
+
: " ✗ 第 0 版目录工具(未配置凭据加密密钥)",
|
|
332
|
+
readiness.registeredInstances > 0
|
|
333
|
+
? ` ✓ 第 1 版实例路由(静态配置 ${readiness.registeredInstances} 个;商家自助绑定在 /instance 页面完成)`
|
|
334
|
+
: " ✓ 第 1 版实例路由(静态配置 0 个;商家可在 /instance 页面自助绑定实例)",
|
|
335
|
+
];
|
|
336
|
+
for (const warning of readiness.warnings) {
|
|
337
|
+
lines.push(` ⚠️ ${warning}`);
|
|
338
|
+
}
|
|
339
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
340
|
+
}
|
|
341
|
+
export async function runGatewayServe(args, env = process.env) {
|
|
342
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
343
|
+
process.stdout.write(USAGE);
|
|
344
|
+
return EXIT.OK;
|
|
345
|
+
}
|
|
346
|
+
const opts = parseGatewayServeArgs(args, env);
|
|
347
|
+
const validation = validateGatewayServeOptions(opts, env);
|
|
348
|
+
if (!validation.ok) {
|
|
349
|
+
process.stderr.write(`${validation.error}\n\n${USAGE}`);
|
|
350
|
+
return EXIT.CONFIG;
|
|
351
|
+
}
|
|
352
|
+
const readiness = validation.readiness;
|
|
353
|
+
if (opts.checkOnly) {
|
|
354
|
+
printReadiness(opts, readiness);
|
|
355
|
+
return EXIT.OK;
|
|
356
|
+
}
|
|
357
|
+
const dataDir = resolveGatewayDataDir(opts.dataDir);
|
|
358
|
+
const db = openGatewayStore(dataDir);
|
|
359
|
+
const oauthStore = new MerchantOAuthStore({ db });
|
|
360
|
+
const credentialSecret = env[opts.credentialKeyEnv];
|
|
361
|
+
const vault = credentialSecret !== undefined && credentialSecret.trim() !== ""
|
|
362
|
+
? new GatewayCredentialVault({ db, secret: credentialSecret })
|
|
363
|
+
: undefined;
|
|
364
|
+
const oauth = new MerchantOAuthServer({
|
|
365
|
+
store: oauthStore,
|
|
366
|
+
issuer: readiness.publicUrl,
|
|
367
|
+
resource: `${readiness.publicUrl}${opts.mcpPath}`,
|
|
368
|
+
connectorSource: opts.source,
|
|
369
|
+
multiMerchant: true,
|
|
370
|
+
// 目录 scope(第 0 版工具)+ 实例 scope(第 1 版工具,经 mcp-proxy 逐次校验)。
|
|
371
|
+
scopes: ["catalog:read", "catalog:write", "merchant:read", "merchant:write"],
|
|
372
|
+
loginPath: "/connect",
|
|
373
|
+
callbackPolicy: {
|
|
374
|
+
...(opts.callbackUri !== undefined ? { expectedCallbackUri: opts.callbackUri } : {}),
|
|
375
|
+
allowLoopbackFallback: opts.allowLoopbackCallback,
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
const publicationClient = new MerchantPublicationClient({ baseUrl: opts.catalogUrl });
|
|
379
|
+
const portalBaseUrl = opts.portalBaseUrl ?? opts.catalogUrl;
|
|
380
|
+
// 商家自助绑定的实例登记(§8.4 第一期):需要加密保管库,缺密钥时不启用。
|
|
381
|
+
const registrations = vault !== undefined ? new InstanceRegistrationStore({ db }) : undefined;
|
|
382
|
+
// 实例注册表 = 运维静态配置 + 商家自助绑定(§8.4)。
|
|
383
|
+
// 凭据来源为 vault 的实例需要加密密钥:缺密钥时**这些实例不启用**
|
|
384
|
+
// (其余静态实例与第 0 版能力不受影响)。
|
|
385
|
+
let staticConfigs = [];
|
|
386
|
+
if ((opts.tenantConfigPath ?? "").trim() !== "") {
|
|
387
|
+
staticConfigs = loadTenantBackendConfigs(readFileSync(String(opts.tenantConfigPath), "utf8"));
|
|
388
|
+
if (vault === undefined) {
|
|
389
|
+
const kept = staticConfigs.filter((c) => c.credentialKind !== "vault");
|
|
390
|
+
if (kept.length < staticConfigs.length) {
|
|
391
|
+
process.stderr.write(`⚠️ 未配置凭据加密密钥:${staticConfigs.length - kept.length} 个 vault 凭据实例未启用\n`);
|
|
392
|
+
}
|
|
393
|
+
staticConfigs = kept;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const tenantRegistry = new TenantBackendRegistry(staticConfigs, env, {
|
|
397
|
+
...(vault !== undefined ? { credentials: vault } : {}),
|
|
398
|
+
...(registrations !== undefined ? { dynamic: { lookup: (id) => registrations.get(id) } } : {}),
|
|
399
|
+
});
|
|
400
|
+
const instanceToolCache = new InstanceToolListCache();
|
|
401
|
+
const handle = await startGatewayEntryServer({
|
|
402
|
+
publicBaseUrl: readiness.publicUrl,
|
|
403
|
+
oauth,
|
|
404
|
+
sessions: new MerchantAdminSessions({ db }),
|
|
405
|
+
identity: new CatalogConnectorIdentityClient({
|
|
406
|
+
baseUrl: opts.catalogUrl,
|
|
407
|
+
connectorToken: String(env[opts.connectorTokenEnv] ?? "").trim(),
|
|
408
|
+
}),
|
|
409
|
+
auth: new MerchantOAuthVerifier({ store: oauthStore, multiMerchant: true }),
|
|
410
|
+
...(vault !== undefined ? { credentials: vault } : {}),
|
|
411
|
+
...(vault !== undefined && registrations !== undefined
|
|
412
|
+
? { instanceBinding: { registrations, credentials: vault } }
|
|
413
|
+
: {}),
|
|
414
|
+
// 每请求按已验证主体组合工具束:第 0 版目录工具 + 该商家的第 1 版实例工具。
|
|
415
|
+
toolsFor: (authorization) => {
|
|
416
|
+
const merchantId = authorization?.merchant_id ?? "";
|
|
417
|
+
if (merchantId === "")
|
|
418
|
+
return undefined;
|
|
419
|
+
const bundles = [];
|
|
420
|
+
if (vault !== undefined) {
|
|
421
|
+
bundles.push(buildCatalogTools(merchantId, {
|
|
422
|
+
client: publicationClient,
|
|
423
|
+
credentials: vault,
|
|
424
|
+
portalBaseUrl,
|
|
425
|
+
}));
|
|
426
|
+
}
|
|
427
|
+
if (tenantRegistry !== undefined && authorization !== undefined) {
|
|
428
|
+
bundles.push(buildInstanceTools({
|
|
429
|
+
registry: tenantRegistry,
|
|
430
|
+
authorization,
|
|
431
|
+
cache: instanceToolCache,
|
|
432
|
+
}));
|
|
433
|
+
}
|
|
434
|
+
return combineScopedTools(bundles);
|
|
435
|
+
},
|
|
436
|
+
...(opts.tlsCertPath !== undefined && opts.tlsKeyPath !== undefined
|
|
437
|
+
? { tls: { certPath: opts.tlsCertPath, keyPath: opts.tlsKeyPath } }
|
|
438
|
+
: {}),
|
|
439
|
+
host: opts.host,
|
|
440
|
+
port: opts.port,
|
|
441
|
+
mcpPath: opts.mcpPath,
|
|
442
|
+
secureCookies: readiness.publicUrl.startsWith("https://"),
|
|
443
|
+
clientLabel: "Kiwi 商家运营",
|
|
444
|
+
serverInfo: { name: "kiwi-merchant-entry", version: "0.1.0" },
|
|
445
|
+
});
|
|
446
|
+
printReadiness(opts, readiness, handle);
|
|
447
|
+
return await new Promise((resolve) => {
|
|
448
|
+
const shutdown = () => {
|
|
449
|
+
void handle.close().then(() => {
|
|
450
|
+
db.close();
|
|
451
|
+
resolve(EXIT.OK);
|
|
452
|
+
});
|
|
453
|
+
};
|
|
454
|
+
process.once("SIGINT", shutdown);
|
|
455
|
+
process.once("SIGTERM", shutdown);
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/merchant-gateway/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAE,8BAA8B,EAAE,MAAM,mDAAmD,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,qBAAqB,GAEtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,uBAAuB,GAExB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,mBAAmB,GAAG,qCAAqC,CAAC;AAClE,2CAA2C;AAC3C,MAAM,CAAC,MAAM,iCAAiC,GAAG,eAAe,CAAC;AACjE,MAAM,2BAA2B,GAAG,8BAA8B,CAAC;AAuBnE,MAAM,UAAU,qBAAqB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,qBAAqB,CACnC,IAAc,EACd,MAA0C,OAAO,CAAC,GAAG;IAErD,MAAM,IAAI,GAAwB;QAChC,UAAU,EAAE,GAAG,CAAC,gBAAgB,IAAI,mBAAmB;QACvD,MAAM,EAAE,iCAAiC;QACzC,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,0BAA0B;QACnC,OAAO,EAAE,qBAAqB,EAAE;QAChC,iBAAiB,EAAE,2BAA2B;QAC9C,gBAAgB,EAAE,6BAA6B;QAC/C,YAAY,EAAE,KAAK;QACnB,qBAAqB,EAAE,IAAI;QAC3B,SAAS,EAAE,KAAK;KACjB,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC/B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,wBAAwB,EAAE,CAAC;YACtC,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;YACnC,SAAS;QACX,CAAC;QACD,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,IAAI,KAAK,cAAc;YAAE,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;aAC/C,IAAI,IAAI,KAAK,eAAe;YAAE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;aACtD,IAAI,IAAI,KAAK,UAAU;YAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;aAC7C,IAAI,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;aACzC,IAAI,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;aACjD,IAAI,IAAI,KAAK,YAAY;YAAE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;aAChD,IAAI,IAAI,KAAK,YAAY;YAAE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;aAChD,IAAI,IAAI,KAAK,uBAAuB;YAAE,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;aACrE,IAAI,IAAI,KAAK,sBAAsB;YAAE,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;aACnE,IAAI,IAAI,KAAK,YAAY;YAAE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;aACpD,IAAI,IAAI,KAAK,WAAW;YAAE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;aAClD,IAAI,IAAI,KAAK,gBAAgB;YAAE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;aACxD,IAAI,IAAI,KAAK,cAAc;YAAE,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;aACxD,IAAI,IAAI,KAAK,iBAAiB;YAAE,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAsBD;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CACzC,IAAyB,EACzB,MAA0C,OAAO,CAAC,GAAG;IAErD,MAAM,YAAY,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,IAAI,YAAY,KAAK,EAAE,EAAE,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,oDAAoD;SAC5D,CAAC;IACJ,CAAC;IACD,IAAI,SAAc,CAAC;IACnB,IAAI,CAAC;QACH,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,YAAY,EAAE,EAAE,CAAC;IACvE,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,KAAK,EAAE,IAAI,SAAS,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC3D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,IAAI,SAAS,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QACrD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3E,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,4CAA4C,YAAY,EAAE;SAClE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;QACxE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,4BAA4B,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IACzE,CAAC;IACD,kCAAkC;IAClC,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IACE,CAAC,UAAU,CAAC,QAAQ,KAAK,OAAO,IAAI,UAAU,CAAC,QAAQ,KAAK,QAAQ,CAAC;YACrE,UAAU,CAAC,QAAQ,KAAK,EAAE;YAC1B,UAAU,CAAC,QAAQ,KAAK,EAAE,EAC1B,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QACrE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IACrE,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IACvD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IACrD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,IAAI,EAAE,EAAE,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,WAAW,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,WAAW,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,mBAAmB,IAAI,CAAC,IAAI,UAAU;gBACtC,yEAAyE;SAC5E,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClE,IAAI,cAAc,KAAK,EAAE,EAAE,CAAC;QAC1B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,QAAQ,IAAI,CAAC,iBAAiB,iCAAiC;gBAC/D,8BAA8B;SACjC,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,aAAa,KAAK,EAAE,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CACX,QAAQ,IAAI,CAAC,gBAAgB,yCAAyC;YACpE,0BAA0B,CAC7B,CAAC;IACJ,CAAC;IACD,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,UAAU,EAAE,EAAE,CAAC;QACzD,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,wBAAwB,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;YAC3E,mBAAmB,GAAG,IAAI,qBAAqB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;QAChE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,GAAG,YAAY,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACrE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,WAAW,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,EAAE,CAAC;QACjD,QAAQ,CAAC,IAAI,CACX,MAAM,IAAI,CAAC,IAAI,yCAAyC;YACtD,WAAW,SAAS,CAAC,MAAM,GAAG,CACjC,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,SAAS,EAAE;YACT,SAAS,EAAE,SAAS,CAAC,MAAM;YAC3B,WAAW,EAAE,mBAAmB,CAAC,IAAI,CAAC,MAAM,EAAE;gBAC5C,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpF,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;aAClD,CAAC;YACF,SAAS,EAAE,OAAO;YAClB,WAAW;YACX,wBAAwB,EAAE,aAAa,KAAK,EAAE;YAC9C,mBAAmB;YACnB,wBAAwB,EAAE,IAAI;YAC9B,QAAQ;SACT;KACF,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,GAAW;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,kDAAkD;AAClD,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,aAAa,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,KAAK,GAAG;;;;;;;+CAOiC,iCAAiC;;yCAEvC,0BAA0B;;;2DAGR,2BAA2B;;;;;;;;;;;;CAYrF,CAAC;AAEF,qCAAqC;AACrC,SAAS,cAAc,CACrB,IAAyB,EACzB,SAAgC,EAChC,MAAiC;IAEjC,MAAM,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IACpF,MAAM,KAAK,GAAG;QACZ,6BAA6B;QAC7B,iBAAiB,SAAS,CAAC,SAAS,EAAE;QACtC,iBAAiB,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,kBAAkB,EAAE;QACpF,kBAAkB,IAAI,CAAC,MAAM,EAAE;QAC/B,mBAAmB,SAAS,CAAC,WAAW,EAAE;QAC1C,iBAAiB,IAAI,CAAC,UAAU,EAAE;QAClC,iBAAiB,IAAI,CAAC,OAAO,EAAE;QAC/B,gBAAgB,SAAS,CAAC,SAAS,mBAAmB;QACtD,aAAa;QACb,uDAAuD;QACvD,oDAAoD,IAAI,CAAC,iBAAiB,aAAa;QACvF,gDAAgD;QAChD,uCAAuC;QACvC,8BAA8B,IAAI,CAAC,gBAAgB,WAAW;QAC9D,KAAK;QACL,+BAA+B;QAC/B,SAAS,CAAC,wBAAwB;YAChC,CAAC,CAAC,sCAAsC;YACxC,CAAC,CAAC,0BAA0B;QAC9B,SAAS,CAAC,mBAAmB,GAAG,CAAC;YAC/B,CAAC,CAAC,sBAAsB,SAAS,CAAC,mBAAmB,4BAA4B;YACjF,CAAC,CAAC,iDAAiD;KACtD,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,QAAQ,OAAO,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAc,EACd,MAA0C,OAAO,CAAC,GAAG;IAErD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IACD,MAAM,IAAI,GAAG,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,2BAA2B,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,OAAO,KAAK,EAAE,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;IACvC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,UAAU,GAAG,IAAI,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,gBAAgB,GAAG,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpD,MAAM,KAAK,GACT,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE;QAC9D,CAAC,CAAC,IAAI,sBAAsB,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QAC9D,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,KAAK,GAAG,IAAI,mBAAmB,CAAC;QACpC,KAAK,EAAE,UAAU;QACjB,MAAM,EAAE,SAAS,CAAC,SAAS;QAC3B,QAAQ,EAAE,GAAG,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE;QACjD,eAAe,EAAE,IAAI,CAAC,MAAM;QAC5B,aAAa,EAAE,IAAI;QACnB,yDAAyD;QACzD,MAAM,EAAE,CAAC,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,CAAC;QAC5E,SAAS,EAAE,UAAU;QACrB,cAAc,EAAE;YACd,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;SAClD;KACF,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,IAAI,yBAAyB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACtF,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,CAAC;IAE5D,yCAAyC;IACzC,MAAM,aAAa,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,yBAAyB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9F,iCAAiC;IACjC,wCAAwC;IACxC,wBAAwB;IACxB,IAAI,aAAa,GAA0B,EAAE,CAAC;IAC9C,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,aAAa,GAAG,wBAAwB,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC;YACvE,IAAI,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC;gBACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gBAAgB,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,oBAAoB,CACvE,CAAC;YACJ,CAAC;YACD,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IACD,MAAM,cAAc,GAAG,IAAI,qBAAqB,CAAC,aAAa,EAAE,GAAG,EAAE;QACnE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/F,CAAC,CAAC;IACH,MAAM,iBAAiB,GAAG,IAAI,qBAAqB,EAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC;QAC3C,aAAa,EAAE,SAAS,CAAC,SAAS;QAClC,KAAK;QACL,QAAQ,EAAE,IAAI,qBAAqB,CAAC,EAAE,EAAE,EAAE,CAAC;QAC3C,QAAQ,EAAE,IAAI,8BAA8B,CAAC;YAC3C,OAAO,EAAE,IAAI,CAAC,UAAU;YACxB,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;SACjE,CAAC;QACF,IAAI,EAAE,IAAI,qBAAqB,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;QAC3E,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,aAAa,KAAK,SAAS;YACpD,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE;YAC5D,CAAC,CAAC,EAAE,CAAC;QACP,4CAA4C;QAC5C,QAAQ,EAAE,CAAC,aAAa,EAAE,EAAE;YAC1B,MAAM,UAAU,GAAG,aAAa,EAAE,WAAW,IAAI,EAAE,CAAC;YACpD,IAAI,UAAU,KAAK,EAAE;gBAAE,OAAO,SAAS,CAAC;YACxC,MAAM,OAAO,GAAsC,EAAE,CAAC;YACtD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,CAAC,IAAI,CACV,iBAAiB,CAAC,UAAU,EAAE;oBAC5B,MAAM,EAAE,iBAAiB;oBACzB,WAAW,EAAE,KAAK;oBAClB,aAAa;iBACd,CAAC,CACH,CAAC;YACJ,CAAC;YACD,IAAI,cAAc,KAAK,SAAS,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;gBAChE,OAAO,CAAC,IAAI,CACV,kBAAkB,CAAC;oBACjB,QAAQ,EAAE,cAAc;oBACxB,aAAa;oBACb,KAAK,EAAE,iBAAiB;iBACzB,CAAC,CACH,CAAC;YACJ,CAAC;YACD,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;YACjE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE;YACnE,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa,EAAE,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC;QACzD,WAAW,EAAE,WAAW;QACxB,UAAU,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,OAAO,EAAE;KAC9D,CAAC,CAAC;IAEH,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAExC,OAAO,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;QAC3C,MAAM,QAAQ,GAAG,GAAS,EAAE;YAC1B,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC5B,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
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 type { DatabaseSync } from "node:sqlite";
|
|
17
|
+
export declare const CREDENTIAL_KEY_ENV = "KIWI_GATEWAY_CREDENTIAL_KEY";
|
|
18
|
+
export interface StoredMerchantCredential {
|
|
19
|
+
token: string;
|
|
20
|
+
expiresAt: string;
|
|
21
|
+
}
|
|
22
|
+
/** 入口需要的凭据保管能力(测试可注入内存实现)。 */
|
|
23
|
+
export interface MerchantCredentialStore {
|
|
24
|
+
put(merchantId: string, token: string, expiresAt: string): void;
|
|
25
|
+
get(merchantId: string): StoredMerchantCredential | undefined;
|
|
26
|
+
delete(merchantId: string): void;
|
|
27
|
+
}
|
|
28
|
+
/** 从环境读取保管密钥;未配置返回 undefined(调用方据此 fail-closed)。 */
|
|
29
|
+
export declare function credentialKeyFromEnv(env?: Record<string, string | undefined>): string | undefined;
|
|
30
|
+
export declare class GatewayCredentialVault implements MerchantCredentialStore {
|
|
31
|
+
private readonly db;
|
|
32
|
+
private readonly key;
|
|
33
|
+
private readonly now;
|
|
34
|
+
constructor(options: {
|
|
35
|
+
db: DatabaseSync;
|
|
36
|
+
secret: string;
|
|
37
|
+
now?: () => string;
|
|
38
|
+
});
|
|
39
|
+
private encrypt;
|
|
40
|
+
private decrypt;
|
|
41
|
+
put(merchantId: string, token: string, expiresAt: string): void;
|
|
42
|
+
get(merchantId: string): StoredMerchantCredential | undefined;
|
|
43
|
+
delete(merchantId: string): void;
|
|
44
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
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
|
+
* 商家连接器入口的凭据保管(AES-256-GCM,密钥来自部署环境)。
|
|
18
|
+
*
|
|
19
|
+
* 入口在商家确认连接时兑换到**目录商家作用域凭据**(`cmt_…`),它需要长期
|
|
20
|
+
* 持有(入口重启后仍要代表该商家读写公开资料)。与既有做法一致,明文不落库:
|
|
21
|
+
* 这里用 `KIWI_GATEWAY_CREDENTIAL_KEY` 派生的 32 字节密钥做 AES-256-GCM
|
|
22
|
+
* 加密后存储,密钥缺失时 fail-closed(入口无法保管凭据 → 商家工具不可用,
|
|
23
|
+
* 而不是退回明文)。
|
|
24
|
+
*
|
|
25
|
+
* 存储位置:入口自己的 oauth.sqlite(0600),表 `gateway_merchant_credentials`。
|
|
26
|
+
* 每个商家一行(merchant_id 主键);重新连接覆盖旧凭据。
|
|
27
|
+
*/
|
|
28
|
+
import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
|
|
29
|
+
export const CREDENTIAL_KEY_ENV = "KIWI_GATEWAY_CREDENTIAL_KEY";
|
|
30
|
+
const VAULT_SCHEMA = `
|
|
31
|
+
CREATE TABLE IF NOT EXISTS gateway_merchant_credentials (
|
|
32
|
+
merchant_id TEXT PRIMARY KEY,
|
|
33
|
+
ciphertext TEXT NOT NULL,
|
|
34
|
+
expires_at TEXT NOT NULL,
|
|
35
|
+
updated_at TEXT NOT NULL
|
|
36
|
+
);
|
|
37
|
+
`;
|
|
38
|
+
/** 从环境读取保管密钥;未配置返回 undefined(调用方据此 fail-closed)。 */
|
|
39
|
+
export function credentialKeyFromEnv(env = process.env) {
|
|
40
|
+
const raw = (env[CREDENTIAL_KEY_ENV] ?? "").trim();
|
|
41
|
+
return raw === "" ? undefined : raw;
|
|
42
|
+
}
|
|
43
|
+
/** 任意长度的部署密钥 → 32 字节 AES 密钥(sha256 派生)。 */
|
|
44
|
+
function deriveKey(secret) {
|
|
45
|
+
return createHash("sha256").update(secret).digest();
|
|
46
|
+
}
|
|
47
|
+
export class GatewayCredentialVault {
|
|
48
|
+
db;
|
|
49
|
+
key;
|
|
50
|
+
now;
|
|
51
|
+
constructor(options) {
|
|
52
|
+
if (typeof options.secret !== "string" || options.secret.trim() === "") {
|
|
53
|
+
throw new Error("GatewayCredentialVault requires a non-empty credential secret");
|
|
54
|
+
}
|
|
55
|
+
this.db = options.db;
|
|
56
|
+
this.key = deriveKey(options.secret);
|
|
57
|
+
this.now = options.now ?? (() => new Date().toISOString());
|
|
58
|
+
this.db.exec(VAULT_SCHEMA);
|
|
59
|
+
}
|
|
60
|
+
encrypt(plaintext) {
|
|
61
|
+
const iv = randomBytes(12);
|
|
62
|
+
const cipher = createCipheriv("aes-256-gcm", this.key, iv);
|
|
63
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
64
|
+
const tag = cipher.getAuthTag();
|
|
65
|
+
return Buffer.concat([iv, tag, ciphertext]).toString("base64");
|
|
66
|
+
}
|
|
67
|
+
decrypt(payload) {
|
|
68
|
+
const raw = Buffer.from(payload, "base64");
|
|
69
|
+
const iv = raw.subarray(0, 12);
|
|
70
|
+
const tag = raw.subarray(12, 28);
|
|
71
|
+
const ciphertext = raw.subarray(28);
|
|
72
|
+
const decipher = createDecipheriv("aes-256-gcm", this.key, iv);
|
|
73
|
+
decipher.setAuthTag(tag);
|
|
74
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
75
|
+
}
|
|
76
|
+
put(merchantId, token, expiresAt) {
|
|
77
|
+
if (merchantId === "" || token === "") {
|
|
78
|
+
throw new Error("credential vault requires merchant_id and token");
|
|
79
|
+
}
|
|
80
|
+
this.db
|
|
81
|
+
.prepare(`INSERT INTO gateway_merchant_credentials(merchant_id, ciphertext, expires_at, updated_at)
|
|
82
|
+
VALUES (?, ?, ?, ?)
|
|
83
|
+
ON CONFLICT(merchant_id) DO UPDATE SET
|
|
84
|
+
ciphertext = excluded.ciphertext,
|
|
85
|
+
expires_at = excluded.expires_at,
|
|
86
|
+
updated_at = excluded.updated_at`)
|
|
87
|
+
.run(merchantId, this.encrypt(token), expiresAt, this.now());
|
|
88
|
+
}
|
|
89
|
+
get(merchantId) {
|
|
90
|
+
const row = this.db
|
|
91
|
+
.prepare("SELECT ciphertext, expires_at FROM gateway_merchant_credentials WHERE merchant_id = ?")
|
|
92
|
+
.get(merchantId);
|
|
93
|
+
if (row === undefined)
|
|
94
|
+
return undefined;
|
|
95
|
+
if (row.expires_at <= this.now())
|
|
96
|
+
return undefined;
|
|
97
|
+
try {
|
|
98
|
+
return { token: this.decrypt(row.ciphertext), expiresAt: row.expires_at };
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// 密钥轮换/数据损坏:当作没有凭据(工具报「需要重新连接」),绝不返回噪音。
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
delete(merchantId) {
|
|
106
|
+
this.db
|
|
107
|
+
.prepare("DELETE FROM gateway_merchant_credentials WHERE merchant_id = ?")
|
|
108
|
+
.run(merchantId);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=credential-vault.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-vault.js","sourceRoot":"","sources":["../../src/merchant-gateway/credential-vault.ts"],"names":[],"mappings":"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"}
|