@tool-bridge/server 0.3.0 → 0.4.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.
Files changed (108) hide show
  1. package/dist/{airtable-V6446SVY.js → airtable-K3I4W27V.js} +6 -4
  2. package/dist/{alt_text_generator_ai-HV7JZPDT.js → alt_text_generator_ai-NE5YYNW3.js} +6 -4
  3. package/dist/{amap-TTTVB6WS.js → amap-C2Y347XH.js} +6 -4
  4. package/dist/{anthropic-JH3RA363.js → anthropic-HEEOKRI7.js} +6 -4
  5. package/dist/{apify-ETNN7ITU.js → apify-4SCWADEP.js} +6 -4
  6. package/dist/{brave_search-3DDR2MMB.js → brave_search-UDLPBEMQ.js} +6 -4
  7. package/dist/{chunk-CSJEZHQO.js → chunk-CYTI7JDJ.js} +13 -82
  8. package/dist/{chunk-JLTYA2B3.js → chunk-F4O6ZRH7.js} +82 -4
  9. package/dist/{chunk-KGYJEEBI.js → chunk-OKQUN7BC.js} +103 -57
  10. package/dist/chunk-TKKRVFMK.js +90 -0
  11. package/dist/{chunk-K7FVSFUX.js → chunk-XE34TXY6.js} +47 -3
  12. package/dist/{circleci-MX3TX3HC.js → circleci-UJEIISGE.js} +6 -4
  13. package/dist/{clerk-MRPORVF4.js → clerk-I2I22BUO.js} +6 -4
  14. package/dist/{cloudflare_dns-OWP7DD7L.js → cloudflare_dns-5M2EY2RS.js} +6 -4
  15. package/dist/{cohere-GPECP66S.js → cohere-XQWLOLCR.js} +6 -4
  16. package/dist/{confluence-BN7LZ6BC.js → confluence-JHCKTQX4.js} +6 -4
  17. package/dist/{convertapi-SBEOFOFQ.js → convertapi-B56OVE2W.js} +7 -5
  18. package/dist/{currencyapi-P2YY7Y7P.js → currencyapi-UPOFZ5P6.js} +6 -4
  19. package/dist/{deepseek-MWB3NYIN.js → deepseek-OS75U3HY.js} +6 -4
  20. package/dist/{docker_hub-3JSCIGQ3.js → docker_hub-LQVDQTQJ.js} +6 -4
  21. package/dist/{dropbox-RFIBDAXO.js → dropbox-HWO6JJ5L.js} +6 -4
  22. package/dist/{dub-YVP57ELQ.js → dub-3J7YEZZ7.js} +6 -4
  23. package/dist/{e2b-NFSUHTZR.js → e2b-KT6W4M6Y.js} +6 -4
  24. package/dist/{exa-KTDY6IV3.js → exa-GWZZ6BWW.js} +6 -4
  25. package/dist/{fal_ai-OCUENLNQ.js → fal_ai-V4AQIJ5K.js} +6 -4
  26. package/dist/{feishu-5CWBQ7E5.js → feishu-GLQBDJMW.js} +12 -4
  27. package/dist/{feishu_custom_bot-ZJR22OK6.js → feishu_custom_bot-TEEZ3BRW.js} +6 -4
  28. package/dist/{figma-YULGANSA.js → figma-N7L3KF4A.js} +6 -4
  29. package/dist/{firehydrant-2V6YSYAP.js → firehydrant-WJT2MLGI.js} +6 -4
  30. package/dist/{fixer-LTCDB3CJ.js → fixer-TG5NW6OA.js} +6 -4
  31. package/dist/{fly-IXPKMAML.js → fly-LYK5NNBG.js} +6 -4
  32. package/dist/{front-KRFB4M5X.js → front-MUQ4YT7O.js} +6 -4
  33. package/dist/{geocodio-VVURKYHQ.js → geocodio-XXB2D3AN.js} +6 -4
  34. package/dist/{ghost-6J2RIOUB.js → ghost-MWYITKQ5.js} +7 -5
  35. package/dist/{github-5Z6KQRYH.js → github-CIBT2UB2.js} +6 -4
  36. package/dist/{gmail-KU4NZ7VA.js → gmail-JZECDA2U.js} +6 -4
  37. package/dist/{googlecalendar-X44DFFXG.js → googlecalendar-ICIIDGEO.js} +6 -4
  38. package/dist/{googledocs-WSGLPKSF.js → googledocs-AV5CHSH3.js} +6 -4
  39. package/dist/{grafana-4PKSSDXY.js → grafana-SJVGZAV5.js} +13 -5
  40. package/dist/{graphhopper-DF65ZNGK.js → graphhopper-ZVBBXBHD.js} +6 -4
  41. package/dist/index.d.ts +39 -0
  42. package/dist/index.js +2 -2
  43. package/dist/{ip2proxy-UCAQ5P2J.js → ip2proxy-EJMBZ4ZQ.js} +6 -4
  44. package/dist/{ipgeolocation_io-UX6FCA2S.js → ipgeolocation_io-7BP766PO.js} +6 -4
  45. package/dist/{ipqualityscore-MKTRXIZJ.js → ipqualityscore-QSB62FH3.js} +6 -4
  46. package/dist/{jina_ai-MRHPCSV5.js → jina_ai-O5GT4ZZZ.js} +6 -4
  47. package/dist/{jira-EG7ZPOIW.js → jira-DFOD6SAV.js} +7 -5
  48. package/dist/{langsmith-FNO3RCOZ.js → langsmith-B5HC4HNY.js} +19 -4
  49. package/dist/{lemlist-SN6BJHSG.js → lemlist-63EOIXDT.js} +6 -4
  50. package/dist/{linear-H3VU4PSD.js → linear-LBQC6RCY.js} +6 -4
  51. package/dist/{logsnag-OY2JJT2H.js → logsnag-YQL67XIX.js} +6 -4
  52. package/dist/main.js +184 -184
  53. package/dist/{mattermost-C5SQ7PGD.js → mattermost-VWLKWU7X.js} +7 -5
  54. package/dist/{mem0-LMLE5BFC.js → mem0-2J5MMVIP.js} +6 -4
  55. package/dist/{memos-UWFAMBZC.js → memos-ANAGWSHJ.js} +13 -5
  56. package/dist/{metabase-SRYDSDJ6.js → metabase-ONSZZ4E2.js} +13 -5
  57. package/dist/{mistral_ai-YNIJ7VDM.js → mistral_ai-FYNVJRRG.js} +7 -5
  58. package/dist/{mother_duck-CPGOFEXE.js → mother_duck-NRSVBZM7.js} +6 -4
  59. package/dist/{ngrok-CDJFBSOM.js → ngrok-FXSVFLEE.js} +6 -4
  60. package/dist/{notes-DIVFH3P3.js → notes-VO45PFNB.js} +10 -3
  61. package/dist/{notion-HGDKS4HK.js → notion-AQH7ZGLG.js} +6 -4
  62. package/dist/{open_exchange_rates-COHHYJDD.js → open_exchange_rates-G3MSI5KX.js} +6 -4
  63. package/dist/{openai-4TRT66GW.js → openai-SZETZOPF.js} +7 -5
  64. package/dist/{opengraph_io-YKVW4PXI.js → opengraph_io-XNV4BFE5.js} +7 -5
  65. package/dist/{openrouter-6CV7B7V5.js → openrouter-TV5LQ55F.js} +6 -4
  66. package/dist/{outline-YWDUK5F7.js → outline-DTZCJ7NR.js} +13 -5
  67. package/dist/{paddle-MEU7HWDZ.js → paddle-T6RK3QSQ.js} +6 -4
  68. package/dist/{perplexity-MRQUDBIC.js → perplexity-MVT3DWR2.js} +6 -4
  69. package/dist/{pinecone-JI7X2TAF.js → pinecone-Z4IVTJMV.js} +6 -4
  70. package/dist/{pipedrive-6JQPAW23.js → pipedrive-PM2PBDDZ.js} +6 -4
  71. package/dist/{polar-7BF56CMC.js → polar-CKXLVP45.js} +6 -4
  72. package/dist/{posthog-YPU5ADEN.js → posthog-QTYLJI3S.js} +20 -5
  73. package/dist/{postmark-BEU5OFKU.js → postmark-V6QQYQ6X.js} +6 -4
  74. package/dist/{prerender-UT5GOOZH.js → prerender-SQAU4FDE.js} +6 -4
  75. package/dist/{pubmed-3SGOE24Q.js → pubmed-6ZMRZYGK.js} +6 -4
  76. package/dist/{railway-CEK4GLRQ.js → railway-PJBDYQYM.js} +12 -4
  77. package/dist/{readwise-DXQUQU67.js → readwise-KJAOWBS5.js} +6 -4
  78. package/dist/{render-7TGAU5AW.js → render-Z2YG43ZD.js} +6 -4
  79. package/dist/{replicate-VICFSQ5A.js → replicate-AXMIH4OJ.js} +6 -4
  80. package/dist/{resend-3E76WK3O.js → resend-HQBXFMOO.js} +6 -4
  81. package/dist/{rootly-36GY46BY.js → rootly-CJW5SJEL.js} +6 -4
  82. package/dist/{scrapfly-VDVUYAHX.js → scrapfly-7APCZZ7V.js} +6 -4
  83. package/dist/{scrapingbee-3KTPMAVY.js → scrapingbee-HTUP6YCA.js} +6 -4
  84. package/dist/{screenshot_fyi-LKG62C3J.js → screenshot_fyi-N6JAOGFQ.js} +6 -4
  85. package/dist/{semantic_scholar-4WREECYO.js → semantic_scholar-METX5XVW.js} +6 -4
  86. package/dist/{sentry-HUQTGXOV.js → sentry-QM7OGZZK.js} +6 -4
  87. package/dist/{shodan-SGRKU4KS.js → shodan-ZPQCN5RX.js} +6 -4
  88. package/dist/{shopify-YCZ4L5HT.js → shopify-FPLQQJXS.js} +6 -4
  89. package/dist/{stripe-OEBKMELB.js → stripe-NNGIPJRH.js} +6 -4
  90. package/dist/{supabase-I3DBY7L4.js → supabase-HKIEC7JZ.js} +6 -4
  91. package/dist/{tavily-B2YHCNRD.js → tavily-WMQVNVQC.js} +6 -4
  92. package/dist/{telegram-2VYJELZX.js → telegram-VP76Z774.js} +7 -5
  93. package/dist/{telnyx-HHXD3CXL.js → telnyx-7BGNYZMU.js} +6 -4
  94. package/dist/{todoist-PHFDEEIS.js → todoist-MXXO72IA.js} +6 -4
  95. package/dist/{trello-WUSAK6YN.js → trello-7RFKIFYN.js} +6 -4
  96. package/dist/{turso-FW56U2B3.js → turso-SVWKUF5Y.js} +6 -4
  97. package/dist/{twilio-M5JI7XHA.js → twilio-WGXCKTR7.js} +6 -4
  98. package/dist/{umami-HAYODRC4.js → umami-2BB5YCC7.js} +6 -4
  99. package/dist/{unsplash-EDPTNEHJ.js → unsplash-W7TX5OXX.js} +6 -4
  100. package/dist/{upstash_redis-GC2CLIWD.js → upstash_redis-YJEWXBBX.js} +6 -4
  101. package/dist/{uptimerobot-XMSNYLIT.js → uptimerobot-BP4BGPOL.js} +6 -4
  102. package/dist/{v2ex-KU4ECD65.js → v2ex-Y2ENEEYQ.js} +6 -4
  103. package/dist/{vercel-THPCEFHW.js → vercel-6EB3NZZP.js} +6 -4
  104. package/dist/{wolfram_alpha_api-WHHTH4GU.js → wolfram_alpha_api-EF3CZMNC.js} +6 -4
  105. package/dist/{wordpress-O6TQEQNF.js → wordpress-JI3YVGXG.js} +7 -5
  106. package/dist/{workos-A3VHHWI3.js → workos-YDK42RA3.js} +6 -4
  107. package/dist/{zhihu-BJAI64YJ.js → zhihu-CNFASBUW.js} +6 -4
  108. package/package.json +3 -3
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  createProviderPlugin,
3
- guardedFetch,
4
3
  requireApiKey,
5
4
  upstreamError
6
- } from "./chunk-CSJEZHQO.js";
7
- import "./chunk-K7FVSFUX.js";
5
+ } from "./chunk-TKKRVFMK.js";
6
+ import {
7
+ guardedFetch
8
+ } from "./chunk-CYTI7JDJ.js";
9
+ import "./chunk-XE34TXY6.js";
8
10
  import {
9
11
  TBError,
10
12
  external_exports
11
- } from "./chunk-JLTYA2B3.js";
13
+ } from "./chunk-F4O6ZRH7.js";
12
14
  import "./chunk-MLKGABMK.js";
13
15
 
14
16
  // ../plugins/src/airtable/api.ts
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  createProviderPlugin,
3
- guardedFetch,
4
3
  requireApiKey,
5
4
  upstreamError
6
- } from "./chunk-CSJEZHQO.js";
7
- import "./chunk-K7FVSFUX.js";
5
+ } from "./chunk-TKKRVFMK.js";
6
+ import {
7
+ guardedFetch
8
+ } from "./chunk-CYTI7JDJ.js";
9
+ import "./chunk-XE34TXY6.js";
8
10
  import {
9
11
  TBError,
10
12
  external_exports
11
- } from "./chunk-JLTYA2B3.js";
13
+ } from "./chunk-F4O6ZRH7.js";
12
14
  import "./chunk-MLKGABMK.js";
13
15
 
14
16
  // ../plugins/src/alt_text_generator_ai/schema.ts
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  createProviderPlugin,
3
- guardedFetch,
4
3
  requireApiKey,
5
4
  upstreamError
6
- } from "./chunk-CSJEZHQO.js";
7
- import "./chunk-K7FVSFUX.js";
5
+ } from "./chunk-TKKRVFMK.js";
6
+ import {
7
+ guardedFetch
8
+ } from "./chunk-CYTI7JDJ.js";
9
+ import "./chunk-XE34TXY6.js";
8
10
  import {
9
11
  TBError,
10
12
  external_exports
11
- } from "./chunk-JLTYA2B3.js";
13
+ } from "./chunk-F4O6ZRH7.js";
12
14
  import "./chunk-MLKGABMK.js";
13
15
 
14
16
  // ../plugins/src/amap/api.ts
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  createProviderPlugin,
3
- guardedFetch,
4
3
  requireApiKey,
5
4
  upstreamError
6
- } from "./chunk-CSJEZHQO.js";
7
- import "./chunk-K7FVSFUX.js";
5
+ } from "./chunk-TKKRVFMK.js";
6
+ import {
7
+ guardedFetch
8
+ } from "./chunk-CYTI7JDJ.js";
9
+ import "./chunk-XE34TXY6.js";
8
10
  import {
9
11
  TBError,
10
12
  external_exports
11
- } from "./chunk-JLTYA2B3.js";
13
+ } from "./chunk-F4O6ZRH7.js";
12
14
  import "./chunk-MLKGABMK.js";
13
15
 
14
16
  // ../plugins/src/anthropic/api.ts
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  createProviderPlugin,
3
- guardedFetch,
4
3
  requireApiKey,
5
4
  upstreamError
6
- } from "./chunk-CSJEZHQO.js";
7
- import "./chunk-K7FVSFUX.js";
5
+ } from "./chunk-TKKRVFMK.js";
6
+ import {
7
+ guardedFetch
8
+ } from "./chunk-CYTI7JDJ.js";
9
+ import "./chunk-XE34TXY6.js";
8
10
  import {
9
11
  TBError,
10
12
  external_exports
11
- } from "./chunk-JLTYA2B3.js";
13
+ } from "./chunk-F4O6ZRH7.js";
12
14
  import "./chunk-MLKGABMK.js";
13
15
 
14
16
  // ../plugins/src/apify/api.ts
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  createProviderPlugin,
3
- guardedFetch,
4
3
  requireApiKey,
5
4
  upstreamError
6
- } from "./chunk-CSJEZHQO.js";
7
- import "./chunk-K7FVSFUX.js";
5
+ } from "./chunk-TKKRVFMK.js";
6
+ import {
7
+ guardedFetch
8
+ } from "./chunk-CYTI7JDJ.js";
9
+ import "./chunk-XE34TXY6.js";
8
10
  import {
9
11
  TBError,
10
12
  external_exports
11
- } from "./chunk-JLTYA2B3.js";
13
+ } from "./chunk-F4O6ZRH7.js";
12
14
  import "./chunk-MLKGABMK.js";
13
15
 
14
16
  // ../plugins/src/brave_search/api.ts
@@ -1,80 +1,6 @@
1
- import {
2
- createPlugin
3
- } from "./chunk-K7FVSFUX.js";
4
1
  import {
5
2
  TBError
6
- } from "./chunk-JLTYA2B3.js";
7
-
8
- // ../plugins/src/_runtime/plugin.ts
9
- function requireApiKey(ctx, service) {
10
- const key = ctx.upstreamAuth;
11
- if (key === void 0 || key === "") {
12
- throw new TBError(
13
- "unavailable",
14
- `${service} \u9700\u8981 API key:\u7ED9\u6302\u8F7D\u8282\u70B9\u914D config.authRef \u6307\u5411\u5DF2\u5B58\u5165 system/secret \u7684\u51ED\u8BC1`
15
- );
16
- }
17
- return key;
18
- }
19
- function requireCredential(ctx, service, field) {
20
- const values = ctx.credentials;
21
- if (values === void 0) {
22
- throw new TBError(
23
- "unavailable",
24
- `${service} \u9700\u8981\u591A\u5B57\u6BB5\u51ED\u8BC1:\u7ED9\u6302\u8F7D\u8282\u70B9\u914D config.authRef \u6307\u5411\u5DF2\u5B58\u5165 system/secret \u7684\u51ED\u8BC1(\u7528 \`tb secret set <name> --field ...\` \u5199\u5165)`
25
- );
26
- }
27
- const value = values[field];
28
- if (value === void 0 || value === "") {
29
- throw new TBError("internal", `${service} \u7684\u51ED\u8BC1\u5B57\u6BB5 '${field}' \u672A\u5728 credentialFields \u91CC\u58F0\u660E`);
30
- }
31
- return value;
32
- }
33
- function createProviderPlugin(input) {
34
- const names = Object.keys(input.actions);
35
- const handlerNames = Object.keys(input.handlers);
36
- const missing = names.filter((name) => !handlerNames.includes(name));
37
- const extra = handlerNames.filter((name) => !names.includes(name));
38
- if (missing.length > 0 || extra.length > 0) {
39
- throw new Error(
40
- `action \u8868\u4E0E handler \u8868\u4E0D\u543B\u5408:\u7F3A handler [${missing.join(", ")}];\u591A\u4F59 handler [${extra.join(", ")}]`
41
- );
42
- }
43
- const plugin = createPlugin({ token: (env) => env.PLUGIN_TOKEN });
44
- const tools = plugin.tools(input.exportId ?? "actions", { description: input.description });
45
- if (input.oauth !== void 0) tools.oauth(input.oauth);
46
- if (input.credentialFields !== void 0) tools.credentials(input.credentialFields);
47
- for (const name of names) {
48
- tools.register(name, input.actions[name], (args, ctx) => input.handlers[name](args, {
49
- upstreamAuth: ctx.upstreamAuth,
50
- credentials: ctx.credentials,
51
- config: ctx.mountConfig
52
- }));
53
- }
54
- if (input.credentialProbe !== void 0) {
55
- const effect = input.actions[input.credentialProbe]?.effect;
56
- if (effect !== "read") {
57
- throw new Error(
58
- `credentialProbe '${input.credentialProbe}' \u7684 effect \u662F '${effect ?? "\u672A\u58F0\u660E"}', \u63A2\u9488\u5FC5\u987B\u662F read \u2014\u2014 \u6302\u8F7D\u65F6\u4F1A\u771F\u5B9E\u8C03\u7528\u5B83`
59
- );
60
- }
61
- tools.probeCredentialWith(input.credentialProbe);
62
- }
63
- return plugin;
64
- }
65
-
66
- // ../plugins/src/_runtime/upstreamError.ts
67
- function upstreamError(status, message) {
68
- if (status === 401) {
69
- return new TBError("permission_denied", message, { httpStatus: 401 });
70
- }
71
- if (status === 403) return new TBError("permission_denied", message);
72
- if (status === 404) return new TBError("not_found", message);
73
- if (status === 409) return new TBError("conflict", message);
74
- if (status === 429) return new TBError("rate_limited", message, { retryable: true });
75
- if (status >= 500) return new TBError("unavailable", message, { retryable: true });
76
- return new TBError("invalid_argument", message);
77
- }
3
+ } from "./chunk-F4O6ZRH7.js";
78
4
 
79
5
  // ../plugins/src/_runtime/ipPolicy.ts
80
6
  function parseIpv4(value) {
@@ -186,10 +112,10 @@ var CROSS_ORIGIN_STRIPPED_HEADERS = [
186
112
  function looksLikeCredentialHeader(name) {
187
113
  return /(?:^|-)(?:api[-_]?key|key|token|secret|auth)(?:$|-)/i.test(name);
188
114
  }
189
- function stripCredentials(headers) {
115
+ function stripCredentials(headers, sensitiveHeaders) {
190
116
  const next = new Headers(headers);
191
117
  for (const [name] of headers) {
192
- if (CROSS_ORIGIN_STRIPPED_HEADERS.includes(name.toLowerCase()) || looksLikeCredentialHeader(name)) {
118
+ if (CROSS_ORIGIN_STRIPPED_HEADERS.includes(name.toLowerCase()) || looksLikeCredentialHeader(name) || sensitiveHeaders.has(name.toLowerCase())) {
193
119
  next.delete(name);
194
120
  }
195
121
  }
@@ -219,7 +145,11 @@ function assertPublicHttpUrl(value) {
219
145
  return url;
220
146
  }
221
147
  function createGuardedFetch(options = {}) {
148
+ const crossOriginRedirect = options.crossOriginRedirect ?? "follow";
222
149
  const maxRedirects = options.maxRedirects ?? MAX_REDIRECTS;
150
+ const sensitiveHeaders = new Set(
151
+ (options.sensitiveHeaders ?? []).map((name) => name.toLowerCase())
152
+ );
223
153
  return async function guardedFetch2(input, init) {
224
154
  const transport = options.fetch ?? globalThis.fetch;
225
155
  const initial = input instanceof Request ? input.url : String(input);
@@ -234,7 +164,11 @@ function createGuardedFetch(options = {}) {
234
164
  }
235
165
  const previousOrigin = new URL(request.url).origin;
236
166
  url = assertPublicHttpUrl(new URL(location, url));
237
- const headers = url.origin === previousOrigin ? request.headers : stripCredentials(request.headers);
167
+ const crossesOrigin = url.origin !== previousOrigin;
168
+ if (crossesOrigin && crossOriginRedirect === "error") {
169
+ throw new EgressBlockedError("\u643A\u5E26\u654F\u611F\u4FE1\u606F\u7684\u51FA\u7AD9\u8BF7\u6C42\u4E0D\u5141\u8BB8\u8DE8\u6E90\u91CD\u5B9A\u5411");
170
+ }
171
+ const headers = !crossesOrigin ? request.headers : stripCredentials(request.headers, sensitiveHeaders);
238
172
  const downgrade = response.status === 303 || (response.status === 301 || response.status === 302) && request.method !== "GET";
239
173
  request = downgrade ? new Request(url, { method: "GET", headers, redirect: "manual" }) : new Request(url, { ...request, headers, redirect: "manual" });
240
174
  }
@@ -243,10 +177,7 @@ function createGuardedFetch(options = {}) {
243
177
  var guardedFetch = createGuardedFetch();
244
178
 
245
179
  export {
246
- requireApiKey,
247
- requireCredential,
248
- createProviderPlugin,
249
- upstreamError,
250
180
  assertPublicHttpUrl,
181
+ createGuardedFetch,
251
182
  guardedFetch
252
183
  };
@@ -15083,23 +15083,53 @@ var NODE_KIND_BY_PROFILE = {
15083
15083
  "tools/v1": "tool",
15084
15084
  "context/v1": "context"
15085
15085
  };
15086
+ function projectExportAuth(exported) {
15087
+ if (exported.oauth !== void 0) return { kind: "oauth" };
15088
+ if (exported.credentialFields !== void 0) {
15089
+ return { kind: "fields", fields: exported.credentialFields };
15090
+ }
15091
+ if (exported.auth?.kind === "none") return { kind: "none" };
15092
+ return {
15093
+ kind: "single",
15094
+ // 兼容旧 descriptor:未显式声明 auth 时沿用“单值但可留空”。
15095
+ required: exported.auth?.required ?? false,
15096
+ ...exported.auth?.label !== void 0 ? { label: exported.auth.label } : {},
15097
+ ...exported.auth?.description !== void 0 ? { description: exported.auth.description } : {}
15098
+ };
15099
+ }
15086
15100
  function projectListItem(entry) {
15087
15101
  const exports = entry.describe.exports;
15088
15102
  const kinds = /* @__PURE__ */ new Set();
15103
+ const exportKinds = {};
15104
+ const exportDetails = {};
15089
15105
  for (const e of exports) {
15090
15106
  const kind = NODE_KIND_BY_PROFILE[e.profile];
15091
- if (kind !== void 0) kinds.add(kind);
15107
+ if (kind !== void 0) {
15108
+ kinds.add(kind);
15109
+ exportKinds[e.id] = kind;
15110
+ exportDetails[e.id] = {
15111
+ id: e.id,
15112
+ kind,
15113
+ auth: projectExportAuth(e),
15114
+ ...e.description !== void 0 ? { description: e.description } : {},
15115
+ ...e.mountConfigFields !== void 0 ? { mountConfigFields: e.mountConfigFields } : {}
15116
+ };
15117
+ }
15092
15118
  }
15093
15119
  const withFields = exports.find((e) => e.credentialFields !== void 0);
15120
+ const withMountConfig = exports.find((e) => e.mountConfigFields !== void 0);
15094
15121
  const description = exports.find((e) => e.description !== void 0)?.description;
15095
15122
  return {
15096
15123
  id: entry.id,
15097
15124
  digest: entry.digest,
15098
15125
  exports: exports.map((e) => e.id),
15126
+ exportKinds,
15127
+ exportDetails,
15099
15128
  nodeKinds: [...kinds].sort(),
15100
15129
  needsOAuth: exports.some((e) => e.oauth !== void 0),
15101
15130
  ...description !== void 0 ? { description } : {},
15102
- ...withFields?.credentialFields !== void 0 ? { credentialFields: withFields.credentialFields } : {}
15131
+ ...withFields?.credentialFields !== void 0 ? { credentialFields: withFields.credentialFields } : {},
15132
+ ...withMountConfig?.mountConfigFields !== void 0 ? { mountConfigFields: withMountConfig.mountConfigFields } : {}
15103
15133
  };
15104
15134
  }
15105
15135
  function matches2(item, query) {
@@ -15396,6 +15426,15 @@ function optionalMethodsForCapabilities(capabilities) {
15396
15426
  return methods;
15397
15427
  }
15398
15428
  var EXPORT_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
15429
+ var exportAuthSchema = external_exports.discriminatedUnion("kind", [
15430
+ external_exports.object({ kind: external_exports.literal("none") }),
15431
+ external_exports.object({
15432
+ kind: external_exports.literal("single"),
15433
+ description: external_exports.string().optional(),
15434
+ label: external_exports.string().optional(),
15435
+ required: external_exports.boolean().optional()
15436
+ })
15437
+ ]);
15399
15438
  var exportSchema = external_exports.object({
15400
15439
  id: external_exports.string().regex(EXPORT_ID_RE, "export id \u987B\u4E3A [A-Za-z0-9._-] \u4E14\u4E0D\u4EE5\u6807\u70B9\u5F00\u5934"),
15401
15440
  profile: external_exports.enum(PLUGIN_PROFILES),
@@ -15403,17 +15442,19 @@ var exportSchema = external_exports.object({
15403
15442
  /** context/v1:实际提供的动词;tools/v1 由运行时 List 发现,可省。 */
15404
15443
  methods: external_exports.array(external_exports.string()).optional(),
15405
15444
  capabilities: external_exports.array(external_exports.string()).optional(),
15445
+ /** export 的单值/无凭证声明;多字段与 OAuth 继续由各自字段表达。 */
15446
+ auth: exportAuthSchema.optional(),
15406
15447
  /**
15407
15448
  * tools/v1 可选:一个**只读、零副作用、无必填入参**的工具名,平台在挂载时拿它做一次
15408
15449
  * 真实调用来验证 `authRef` 指向的凭证可用(见 `credentialProbe` 的类型注释)。
15409
15450
  */
15410
15451
  credentialProbe: external_exports.string().optional(),
15411
15452
  /**
15412
- * 多字段凭证的字段声明(tools/v1)。声明了它,平台就知道该 secret 存的是一个 JSON
15453
+ * 多字段凭证的字段声明(tools/v1)。声明了它,平台就知道该 secret 存的是一个 JSON
15413
15454
  * 对象而非单值,并在挂载时校验字段齐全 —— 见 `credentialFields` 的类型注释。
15414
15455
  */
15415
15456
  /**
15416
- * provider 型 OAuth2 的声明(tools/v1)。声明了它,平台就托管授权码流程:
15457
+ * provider 型 OAuth2 的声明(tools/v1)。声明了它,平台就托管授权码流程:
15417
15458
  * `POST /<path>/~authorize` 发起、回调兑换、调用时自动刷新,插件只拿到 access token。
15418
15459
  */
15419
15460
  oauth: pluginOAuthSchema.optional(),
@@ -15424,6 +15465,17 @@ var exportSchema = external_exports.object({
15424
15465
  required: external_exports.boolean().optional(),
15425
15466
  /** 敏感字段:管理面不回显、日志不打印。缺省按敏感处理(fail safe)。 */
15426
15467
  secret: external_exports.boolean().optional()
15468
+ })).min(1).optional(),
15469
+ /**
15470
+ * 非凭证的挂载配置字段(如 baseUrl / instanceUrl / region)。声明了它,平台就知道
15471
+ * 该 export 挂载时还需要哪些 `providerConfig`,管理面据此渲染带标签的输入框而不是让
15472
+ * 用户对着一个自由 k=v 框猜 —— 见 `mountConfigFields` 的类型注释。
15473
+ */
15474
+ mountConfigFields: external_exports.array(external_exports.object({
15475
+ key: external_exports.string().regex(/^[A-Za-z_][\w]*$/, "\u5B57\u6BB5\u540D\u987B\u4E3A\u5408\u6CD5\u6807\u8BC6\u7B26"),
15476
+ label: external_exports.string().optional(),
15477
+ description: external_exports.string().optional(),
15478
+ required: external_exports.boolean().optional()
15427
15479
  })).min(1).optional()
15428
15480
  });
15429
15481
  var describeSchema = external_exports.object({
@@ -15453,6 +15505,20 @@ function validatePluginContract(input) {
15453
15505
  throw new TBError("invalid_argument", `plugin '${manifest.id}' \u7684 export id \u91CD\u590D:'${exported.id}'`);
15454
15506
  }
15455
15507
  seen.add(exported.id);
15508
+ if (exported.auth !== void 0) {
15509
+ if (exported.oauth !== void 0 || exported.credentialFields !== void 0) {
15510
+ throw new TBError(
15511
+ "invalid_argument",
15512
+ `plugin '${manifest.id}' export '${exported.id}' \u7684 auth \u4E0D\u80FD\u4E0E oauth/credentialFields \u540C\u65F6\u58F0\u660E`
15513
+ );
15514
+ }
15515
+ if (exported.auth.kind === "none" && exported.credentialProbe !== void 0) {
15516
+ throw new TBError(
15517
+ "invalid_argument",
15518
+ `plugin '${manifest.id}' export '${exported.id}' \u58F0\u660E auth:none,\u4E0D\u80FD\u518D\u58F0\u660E credentialProbe`
15519
+ );
15520
+ }
15521
+ }
15456
15522
  if (exported.credentialProbe !== void 0 && exported.profile !== "tools/v1") {
15457
15523
  throw new TBError(
15458
15524
  "invalid_argument",
@@ -15497,6 +15563,18 @@ function validatePluginContract(input) {
15497
15563
  keys.add(field.key);
15498
15564
  }
15499
15565
  }
15566
+ if (exported.mountConfigFields !== void 0) {
15567
+ const keys = /* @__PURE__ */ new Set();
15568
+ for (const field of exported.mountConfigFields) {
15569
+ if (keys.has(field.key)) {
15570
+ throw new TBError(
15571
+ "invalid_argument",
15572
+ `plugin '${manifest.id}' export '${exported.id}' \u7684 mountConfigFields \u6709\u91CD\u590D\u5B57\u6BB5 '${field.key}'`
15573
+ );
15574
+ }
15575
+ keys.add(field.key);
15576
+ }
15577
+ }
15500
15578
  if (exported.profile === "context/v1") {
15501
15579
  const known = new Set(CONTEXT_METHODS);
15502
15580
  const unknown2 = (exported.methods ?? []).filter((m) => !known.has(m));
@@ -130,7 +130,7 @@ import {
130
130
  url,
131
131
  validatePath,
132
132
  virtualizeTools
133
- } from "./chunk-JLTYA2B3.js";
133
+ } from "./chunk-F4O6ZRH7.js";
134
134
 
135
135
  // src/config.ts
136
136
  var DEFAULT_PORT = 8787;
@@ -650,53 +650,6 @@ function createS3ObjectStore(cfg, opts) {
650
650
  };
651
651
  }
652
652
 
653
- // ../app/src/deviceNodes.ts
654
- function tbErrorFromBody(body) {
655
- return new TBError(body.code, body.message, { retryable: body.retryable });
656
- }
657
- function requireDevice(deps) {
658
- if (deps.device === void 0) {
659
- throw TBError.unimplemented("device capability disabled: no device transport");
660
- }
661
- return deps.device;
662
- }
663
- async function invokeDevice(deps, deviceId, req) {
664
- const id = crypto.randomUUID();
665
- const body = await requireDevice(deps).invoke(deviceId, { id, ...req });
666
- if (!body || !("ok" in body)) {
667
- throw new TBError("unavailable", "device session returned invalid result");
668
- }
669
- if (body.ok) return body.value;
670
- throw tbErrorFromBody(body.error);
671
- }
672
- function deviceMarkerOf(pc) {
673
- if (pc === void 0 || typeof pc.deviceId !== "string" || typeof pc.mountPath !== "string") {
674
- return null;
675
- }
676
- return {
677
- deviceId: pc.deviceId,
678
- mountPath: pc.mountPath,
679
- ...Array.isArray(pc.cmds) ? { cmds: pc.cmds } : {}
680
- };
681
- }
682
- function deviceToolMarker(node) {
683
- if (node.kind !== "tool" || node.config?.kind !== "tool") return null;
684
- return deviceMarkerOf(node.config.providerConfig);
685
- }
686
- function relativeDevicePath(nodePath, mountPath) {
687
- if (nodePath.startsWith(`${mountPath}/`)) return nodePath.slice(mountPath.length + 1);
688
- throw new TBError("invalid_argument", `device \u8282\u70B9 '${nodePath}' \u4E0D\u5728\u6302\u8F7D '${mountPath}' \u4E0B`);
689
- }
690
- function assertNoDeviceMarker(config) {
691
- const pc = config.providerConfig;
692
- if (pc !== null && typeof pc === "object" && deviceMarkerOf(pc) !== null) {
693
- throw new TBError(
694
- "invalid_argument",
695
- "providerConfig \u7684 device \u8F6C\u53D1\u6807\u8BB0\u7531\u7F51\u5173\u4EE3\u5199,\u4E0D\u5F97\u7ECF\u6CE8\u518C\u9762\u643A\u5E26"
696
- );
697
- }
698
- }
699
-
700
653
  // ../app/src/providers/toolCache.ts
701
654
  var KEY_PREFIX = "toolcache:";
702
655
  function toolCacheKey(path) {
@@ -992,6 +945,53 @@ var SearchSynchronizer = class {
992
945
  // ../app/src/deps.ts
993
946
  var TOOL_CACHE_TTL_DEFAULT = 300;
994
947
 
948
+ // ../app/src/deviceNodes.ts
949
+ function tbErrorFromBody(body) {
950
+ return new TBError(body.code, body.message, { retryable: body.retryable });
951
+ }
952
+ function requireDevice(deps) {
953
+ if (deps.device === void 0) {
954
+ throw TBError.unimplemented("device capability disabled: no device transport");
955
+ }
956
+ return deps.device;
957
+ }
958
+ async function invokeDevice(deps, deviceId, req) {
959
+ const id = crypto.randomUUID();
960
+ const body = await requireDevice(deps).invoke(deviceId, { id, ...req });
961
+ if (!body || !("ok" in body)) {
962
+ throw new TBError("unavailable", "device session returned invalid result");
963
+ }
964
+ if (body.ok) return body.value;
965
+ throw tbErrorFromBody(body.error);
966
+ }
967
+ function deviceMarkerOf(pc) {
968
+ if (pc === void 0 || typeof pc.deviceId !== "string" || typeof pc.mountPath !== "string") {
969
+ return null;
970
+ }
971
+ return {
972
+ deviceId: pc.deviceId,
973
+ mountPath: pc.mountPath,
974
+ ...Array.isArray(pc.cmds) ? { cmds: pc.cmds } : {}
975
+ };
976
+ }
977
+ function deviceToolMarker(node) {
978
+ if (node.kind !== "tool" || node.config?.kind !== "tool") return null;
979
+ return deviceMarkerOf(node.config.providerConfig);
980
+ }
981
+ function relativeDevicePath(nodePath, mountPath) {
982
+ if (nodePath.startsWith(`${mountPath}/`)) return nodePath.slice(mountPath.length + 1);
983
+ throw new TBError("invalid_argument", `device \u8282\u70B9 '${nodePath}' \u4E0D\u5728\u6302\u8F7D '${mountPath}' \u4E0B`);
984
+ }
985
+ function assertNoDeviceMarker(config) {
986
+ const pc = config.providerConfig;
987
+ if (pc !== null && typeof pc === "object" && deviceMarkerOf(pc) !== null) {
988
+ throw new TBError(
989
+ "invalid_argument",
990
+ "providerConfig \u7684 device \u8F6C\u53D1\u6807\u8BB0\u7531\u7F51\u5173\u4EE3\u5199,\u4E0D\u5F97\u7ECF\u6CE8\u518C\u9762\u643A\u5E26"
991
+ );
992
+ }
993
+ }
994
+
995
995
  // ../app/src/providers/http.ts
996
996
  function toSpec(t) {
997
997
  const spec = { name: t.name, description: t.description, effect: effectFor(t) };
@@ -19265,6 +19265,47 @@ function mountCallContext(ctx, mountPath, providerConfig, exportId) {
19265
19265
  ...exportId !== void 0 ? { exportId } : {}
19266
19266
  };
19267
19267
  }
19268
+ async function assertPluginMountContract(exported, config, deps) {
19269
+ const providerConfig = config.providerConfig ?? {};
19270
+ const missingConfig = (exported.mountConfigFields ?? []).filter((field) => {
19271
+ if (field.required !== true) return false;
19272
+ const value = providerConfig[field.key];
19273
+ return value === void 0 || value === null || typeof value === "string" && value.trim() === "";
19274
+ }).map((field) => field.key);
19275
+ if (missingConfig.length > 0) {
19276
+ throw new TBError(
19277
+ "invalid_argument",
19278
+ `plugin export '${exported.id}' \u7F3A\u5C11\u5FC5\u586B providerConfig:${missingConfig.join(", ")}`
19279
+ );
19280
+ }
19281
+ const authRef = typeof config.authRef === "string" && config.authRef.trim() !== "" ? config.authRef.trim() : void 0;
19282
+ if (exported.auth?.kind === "none") {
19283
+ if (authRef !== void 0) {
19284
+ throw new TBError(
19285
+ "invalid_argument",
19286
+ `plugin export '${exported.id}' \u58F0\u660E auth:none,\u4E0D\u5F97\u7ED1\u5B9A authRef`
19287
+ );
19288
+ }
19289
+ return;
19290
+ }
19291
+ const requiresAuth = exported.oauth !== void 0 || exported.credentialFields !== void 0 || exported.auth?.kind === "single" && exported.auth.required === true;
19292
+ if (requiresAuth && authRef === void 0) {
19293
+ throw new TBError(
19294
+ "invalid_argument",
19295
+ `plugin export '${exported.id}' \u9700\u8981 authRef`
19296
+ );
19297
+ }
19298
+ if (authRef === void 0) return;
19299
+ const raw = await deps.secrets.resolve(authRef);
19300
+ if (raw === void 0) {
19301
+ throw new TBError("invalid_argument", `secret '${authRef}' \u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u89E3\u5BC6`);
19302
+ }
19303
+ if (exported.credentialFields !== void 0) {
19304
+ parseCredentialValues(raw, exported.credentialFields);
19305
+ } else if (exported.oauth !== void 0) {
19306
+ parseCredentialValues(raw, [...OAUTH_CLIENT_FIELDS]);
19307
+ }
19308
+ }
19268
19309
  async function providerAccessTokenFor(opts) {
19269
19310
  const encryptionKey = opts.deps.encryptionKey;
19270
19311
  if (encryptionKey === void 0) {
@@ -19452,13 +19493,11 @@ async function assertToolConfig(config, deps, ctx, mountPath) {
19452
19493
  typeof exportId === "string" ? exportId : void 0
19453
19494
  );
19454
19495
  const authRef = config.authRef;
19455
- if (exported.credentialFields !== void 0 && typeof authRef === "string") {
19456
- const raw = await deps.secrets.resolve(authRef);
19457
- if (raw === void 0) {
19458
- throw new TBError("invalid_argument", `secret '${authRef}' \u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u89E3\u5BC6`);
19459
- }
19460
- parseCredentialValues(raw, exported.credentialFields);
19461
- }
19496
+ await assertPluginMountContract(
19497
+ exported,
19498
+ config,
19499
+ deps
19500
+ );
19462
19501
  if (exported.credentialProbe === void 0 || typeof authRef !== "string" || ctx === void 0 || mountPath === void 0 || exported.oauth !== void 0) {
19463
19502
  return;
19464
19503
  }
@@ -19713,7 +19752,14 @@ async function assertContextConfig(config, deps) {
19713
19752
  assertNoDeviceMarker(config);
19714
19753
  const cfg = config;
19715
19754
  if (cfg.provider !== "r2" && cfg.provider !== "s3") {
19716
- await requirePluginExport(deps, cfg.provider, "context", "context", cfg.export);
19755
+ const { export: exported } = await requirePluginExport(
19756
+ deps,
19757
+ cfg.provider,
19758
+ "context",
19759
+ "context",
19760
+ cfg.export
19761
+ );
19762
+ await assertPluginMountContract(exported, cfg, deps);
19717
19763
  return;
19718
19764
  }
19719
19765
  if (cfg.provider === "s3") {
@@ -38291,7 +38337,7 @@ import { join as join4 } from "path";
38291
38337
  // package.json
38292
38338
  var package_default = {
38293
38339
  name: "@tool-bridge/server",
38294
- version: "0.3.0",
38340
+ version: "0.4.0",
38295
38341
  description: "tool-bridge self-hosted server: run the HTBP gateway on Node with SQLite persistence, filesystem object storage and WebSocket device channel \u2014 single container via docker run",
38296
38342
  type: "module",
38297
38343
  license: "MIT",