@tool-bridge/server 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/dist/{airtable-S3T4TAN7.js → airtable-NOSOMOVB.js} +106 -114
  2. package/dist/{alt_text_generator_ai-4DIRIDKL.js → alt_text_generator_ai-BHIJ4LW5.js} +25 -16
  3. package/dist/{amap-LGVGNPML.js → amap-QRLP4TWZ.js} +114 -123
  4. package/dist/{anthropic-27RFZO35.js → anthropic-IEOI36EV.js} +34 -56
  5. package/dist/{apify-6WLYAIAS.js → apify-3CCYTQVK.js} +31 -49
  6. package/dist/{brave_search-K2SVJ66F.js → brave_search-PZNYDQG7.js} +52 -77
  7. package/dist/chunk-JXHMDBAY.js +45 -0
  8. package/dist/chunk-LMLX3DJF.js +50 -0
  9. package/dist/{chunk-YB2FLNWI.js → chunk-RVWZN3CI.js} +2103 -1775
  10. package/dist/{chunk-BB6ZLMTU.js → chunk-TLNUIPFZ.js} +492 -300
  11. package/dist/chunk-U5UHT7CX.js +977 -0
  12. package/dist/chunk-U67V476Y.js +35 -0
  13. package/dist/chunk-WW2IMPQK.js +283 -0
  14. package/dist/{chunk-VK3V2WTY.js → chunk-YASUMV2K.js} +4 -6
  15. package/dist/{circleci-WV3ITU7Q.js → circleci-VSJ4O5FC.js} +36 -55
  16. package/dist/{clerk-NFQEFKS4.js → clerk-CC2JZBZI.js} +60 -80
  17. package/dist/{cloudflare_dns-2RK5ASBJ.js → cloudflare_dns-PJEBSEYQ.js} +90 -113
  18. package/dist/{cohere-5KEW7LWT.js → cohere-KBACYSPF.js} +33 -49
  19. package/dist/{confluence-SZE63S46.js → confluence-2PX3O7G5.js} +79 -115
  20. package/dist/{convertapi-QPG2JC5K.js → convertapi-BVOTD2PJ.js} +13 -16
  21. package/dist/{currencyapi-UO2APQRY.js → currencyapi-6ZQ2VNQ7.js} +30 -53
  22. package/dist/{deepseek-LJELIMM3.js → deepseek-MB3WVVTB.js} +30 -38
  23. package/dist/{docker_hub-2MFXSBOF.js → docker_hub-7CLQL2IJ.js} +141 -157
  24. package/dist/{dropbox-GQYNTTVA.js → dropbox-VFYDVUNK.js} +134 -141
  25. package/dist/{dub-KI2LHXST.js → dub-QN3EETJY.js} +61 -93
  26. package/dist/{e2b-WO6ISY3C.js → e2b-NKC3Y776.js} +39 -69
  27. package/dist/{exa-IZ7B3BPT.js → exa-KKZ6F25K.js} +49 -77
  28. package/dist/{fal_ai-LTMF36GJ.js → fal_ai-25LYJD2O.js} +37 -44
  29. package/dist/{feishu-WM7SLSFD.js → feishu-NRT55B3Q.js} +4 -6
  30. package/dist/{feishu_custom_bot-66W3MXH2.js → feishu_custom_bot-3W3XXUG4.js} +4 -5
  31. package/dist/{figma-2Z274VQZ.js → figma-4FLP35TC.js} +56 -81
  32. package/dist/{firehydrant-IFI4R65V.js → firehydrant-BLXPLZ3X.js} +40 -53
  33. package/dist/{fixer-BCCZEB3D.js → fixer-4OR62TGE.js} +31 -43
  34. package/dist/{fly-755FXYB5.js → fly-MYCKOZZK.js} +50 -66
  35. package/dist/{front-4FZKKXXK.js → front-3DFYVMF3.js} +43 -66
  36. package/dist/{geocodio-WYKDJ3DP.js → geocodio-CXMD6VKA.js} +37 -63
  37. package/dist/{ghost-5BNQTCOH.js → ghost-4UUE737W.js} +51 -57
  38. package/dist/{github-ULELF5VX.js → github-WFS2ON2N.js} +48 -41
  39. package/dist/{gmail-G34WT64J.js → gmail-KW7FXA7A.js} +26 -36
  40. package/dist/{googlecalendar-BQU255SC.js → googlecalendar-AMH5JQMC.js} +57 -78
  41. package/dist/{googledocs-HPCNQXYJ.js → googledocs-R5VA6CKD.js} +14 -22
  42. package/dist/{grafana-VOV24FIC.js → grafana-IT6DWIVB.js} +95 -122
  43. package/dist/{graphhopper-D5RXW6AP.js → graphhopper-TYFDJZWC.js} +32 -46
  44. package/dist/index.d.ts +57 -50
  45. package/dist/index.js +4 -3
  46. package/dist/{ip2proxy-DAYO7EKZ.js → ip2proxy-GJ4HXVXO.js} +35 -42
  47. package/dist/{ipgeolocation_io-XD4PSLII.js → ipgeolocation_io-OAGR6PRF.js} +40 -60
  48. package/dist/{ipqualityscore-K27QEAWK.js → ipqualityscore-BCKAMDGL.js} +30 -42
  49. package/dist/{jina_ai-E6UXFV2P.js → jina_ai-N3NXRVIZ.js} +32 -58
  50. package/dist/{jira-ZDSXGQ6W.js → jira-CHLBKWLO.js} +116 -126
  51. package/dist/{langsmith-TIFJRREW.js → langsmith-OIKOTPY3.js} +101 -121
  52. package/dist/{lemlist-DASEMJMA.js → lemlist-VAKYPKS3.js} +57 -68
  53. package/dist/{linear-KE6UP4SP.js → linear-Q6QTPJ5R.js} +109 -118
  54. package/dist/{logsnag-IMNDN4R5.js → logsnag-SQOQBTES.js} +31 -48
  55. package/dist/main.js +103 -102
  56. package/dist/{mattermost-HHHMUXQA.js → mattermost-G2KBEICM.js} +45 -62
  57. package/dist/{mem0-D2FGGOIY.js → mem0-D2FPLYDX.js} +72 -98
  58. package/dist/{memos-4OVIGFPH.js → memos-76PTWV5V.js} +68 -122
  59. package/dist/{metabase-33WCX5YD.js → metabase-TWSIDVBM.js} +47 -60
  60. package/dist/{mistral_ai-QIMZ2JYL.js → mistral_ai-TP7TQUEJ.js} +35 -40
  61. package/dist/{mother_duck-M6VWS2VH.js → mother_duck-UXY5THYU.js} +42 -62
  62. package/dist/{ngrok-Z2PKQBHH.js → ngrok-RZW2ISJK.js} +42 -58
  63. package/dist/{notes-SS4RPC4K.js → notes-B2I6FWK2.js} +3 -5
  64. package/dist/{notion-FJCNQ6I7.js → notion-QOKRUE6M.js} +83 -97
  65. package/dist/{open_exchange_rates-WU57WTT5.js → open_exchange_rates-ODLFWEJ7.js} +35 -39
  66. package/dist/{openai-JODZ4GKT.js → openai-ZPBPPPGT.js} +51 -55
  67. package/dist/{opengraph_io-SQRAUSV5.js → opengraph_io-EOI5UJKT.js} +61 -79
  68. package/dist/{openrouter-Q5XXEJZ7.js → openrouter-BUWLF3BG.js} +41 -55
  69. package/dist/{outline-RT2EHJ2X.js → outline-NXS3QRXO.js} +89 -104
  70. package/dist/{paddle-OF2V7GAC.js → paddle-T4MSKQ76.js} +34 -49
  71. package/dist/{perplexity-LNZEWLHG.js → perplexity-WW5N2LW7.js} +33 -50
  72. package/dist/{pinecone-JSJIXZYN.js → pinecone-RY5AZPQM.js} +65 -91
  73. package/dist/{pipedrive-D4CKVUXR.js → pipedrive-OHYQNZTU.js} +37 -59
  74. package/dist/{polar-M7ZYP6UR.js → polar-XZIAHXS5.js} +43 -53
  75. package/dist/{posthog-YV7CZOH4.js → posthog-DTPTWORY.js} +58 -77
  76. package/dist/{postmark-KYHLECRG.js → postmark-F4UCQKC3.js} +52 -71
  77. package/dist/{prerender-HCMHBKV2.js → prerender-P3Y2MLIC.js} +32 -50
  78. package/dist/{pubmed-WYVLCCN3.js → pubmed-RHU3GXFB.js} +28 -60
  79. package/dist/{railway-TWIRD5KR.js → railway-VB6SRLI6.js} +32 -39
  80. package/dist/{readwise-UZ467IQ7.js → readwise-DIMSKJZR.js} +62 -78
  81. package/dist/{render-MECUC5CC.js → render-XCCDCEEK.js} +48 -64
  82. package/dist/{replicate-A5MEK3SW.js → replicate-IUEOQ4JC.js} +41 -58
  83. package/dist/{resend-BC6EAWJQ.js → resend-N5MJZH5E.js} +27 -37
  84. package/dist/{rootly-ZM3QDUIS.js → rootly-25T4NBTU.js} +64 -76
  85. package/dist/{scrapfly-WAML42QJ.js → scrapfly-PK4XFXUA.js} +45 -51
  86. package/dist/{scrapingbee-DG7PET3V.js → scrapingbee-ITPBMWQU.js} +25 -33
  87. package/dist/{screenshot_fyi-HY6WTHIO.js → screenshot_fyi-5U6ZYPKR.js} +29 -47
  88. package/dist/{semantic_scholar-C5IZA7IP.js → semantic_scholar-BJGCI2MU.js} +37 -56
  89. package/dist/{sentry-OKBPSTDM.js → sentry-63IC263P.js} +66 -85
  90. package/dist/{shodan-PPC6DYU4.js → shodan-2WBIFHFN.js} +42 -53
  91. package/dist/{shopify-EWGUHBXO.js → shopify-XLLJRAGM.js} +32 -49
  92. package/dist/{stripe-6RPDPC5W.js → stripe-WLVCY3UN.js} +4 -5
  93. package/dist/{supabase-SK7DQ42N.js → supabase-BKNZ35ER.js} +69 -88
  94. package/dist/{tavily-YCG5VQMH.js → tavily-YFSDEUTL.js} +37 -62
  95. package/dist/{telegram-2OES5FYB.js → telegram-FC35W74G.js} +168 -177
  96. package/dist/{telnyx-POOSBBR4.js → telnyx-MI32XZUG.js} +30 -50
  97. package/dist/{todoist-M7YD6YSS.js → todoist-4ZFJKZC6.js} +77 -89
  98. package/dist/{trello-IS6V5W3E.js → trello-UOGFNMK4.js} +108 -122
  99. package/dist/{turso-RCFHUFVH.js → turso-YTSTW3ZS.js} +52 -64
  100. package/dist/{twilio-OS2RXFGO.js → twilio-XAJDFUQH.js} +48 -55
  101. package/dist/{umami-PQ2SJ2LN.js → umami-ZVIUBPAI.js} +49 -69
  102. package/dist/{unsplash-C6BPZO4E.js → unsplash-IU3PLDNS.js} +35 -52
  103. package/dist/{upstash_redis-WH6UER7H.js → upstash_redis-3EYJW7SY.js} +28 -40
  104. package/dist/{uptimerobot-M3YZGS6Z.js → uptimerobot-PJG2ASRU.js} +11 -12
  105. package/dist/{v2ex-R4JWTEHN.js → v2ex-KFQWWGFC.js} +36 -61
  106. package/dist/{vercel-FZVYUOQD.js → vercel-I2ZDOQRL.js} +124 -150
  107. package/dist/{webapi-VLM4IKVB.js → webapi-GW5QXWXE.js} +1 -1
  108. package/dist/{wolfram_alpha_api-2KOLO5DC.js → wolfram_alpha_api-BNXOJMB6.js} +26 -34
  109. package/dist/{wordpress-XRWGO6LG.js → wordpress-36D7BSMP.js} +87 -104
  110. package/dist/{workos-WR4NKOYL.js → workos-6X4JJRRC.js} +37 -56
  111. package/dist/{zhihu-BKZIB3WA.js → zhihu-CIXKCHIU.js} +35 -57
  112. package/package.json +5 -5
  113. package/dist/chunk-2O27H4Y2.js +0 -183
  114. package/dist/chunk-GKX72JMJ.js +0 -378
  115. package/dist/chunk-MLKGABMK.js +0 -9
@@ -1,3 +1,6 @@
1
+ import {
2
+ createGuardedFetch
3
+ } from "./chunk-U5UHT7CX.js";
1
4
  import {
2
5
  AnnotationStore,
3
6
  CONTEXT_CAPABILITIES,
@@ -27,7 +30,6 @@ import {
27
30
  PG_SEARCH_TOOLS_TABLE,
28
31
  PG_SEARCH_WRITE_LOCK_KEY,
29
32
  PRESIGN_TTL_SEC_DEFAULT,
30
- PRESIGN_TTL_SEC_MAX,
31
33
  RemoteAllowlistStore,
32
34
  SKILLHUB_CAPABILITIES,
33
35
  SKRegistryStore,
@@ -88,11 +90,24 @@ import {
88
90
  deviceFsHelpModel,
89
91
  deviceShellHelpModel,
90
92
  discriminatedUnion,
93
+ dispatchContextCmd,
94
+ dispatchContextUploadCmd,
95
+ dispatchSkillhubCmd,
91
96
  effectFor,
92
97
  email,
93
98
  encodeCallContext,
94
99
  encodeDeviceFrame,
95
100
  encodePluginCall,
101
+ external_exports,
102
+ feedbackDetailSchema,
103
+ feedbackListSchema,
104
+ feedbackRemoveResponseSchema,
105
+ feedbackSubmitRequestSchema,
106
+ feedbackSubmitResponseSchema,
107
+ feedbackViewSchema,
108
+ feedbackVoteRequestSchema,
109
+ healthResponseSchema,
110
+ helpJsonSchema,
96
111
  identify,
97
112
  intersection,
98
113
  isContextExpired,
@@ -101,23 +116,30 @@ import {
101
116
  iso_exports,
102
117
  lazy,
103
118
  literal,
119
+ livenessResponseSchema,
104
120
  looseObject,
105
121
  mintKey,
106
122
  negotiate,
107
- normalizeCanonicalOrigin,
123
+ nodeInputSchema,
108
124
  normalizeEntryPath,
109
125
  normalizePath,
110
126
  normalizeToolSearchLimit,
111
127
  normalizeToolSearchPath,
112
128
  normalizeUpstreamError,
113
129
  number,
130
+ oauthAuthorizeRequestSchema,
131
+ oauthAuthorizeResponseSchema,
114
132
  object,
115
133
  objectBodyToBytes,
116
134
  optional,
117
135
  optionalMethodsForCapabilities,
136
+ parseContextCmdArgs,
118
137
  parseCredentialValues,
119
138
  parseFeedbackEntries,
120
139
  parseNodeInput,
140
+ parseNonNegativeIntEnv,
141
+ parsePortEnv,
142
+ parseRuntimeEnv,
121
143
  parseTokenResponse,
122
144
  parseVia,
123
145
  pgBulkInsertSql,
@@ -125,7 +147,9 @@ import {
125
147
  pluginTokenSecretName,
126
148
  prefixUpperBound,
127
149
  preprocess,
150
+ readinessResponseSchema,
128
151
  record,
152
+ registryNodeSchema,
129
153
  renderHelpDsl,
130
154
  renderHelpJson,
131
155
  renderHelpMarkdown,
@@ -141,59 +165,39 @@ import {
141
165
  skillhubScopeForCmd,
142
166
  storeUri,
143
167
  string,
168
+ tbErrorBodySchema,
144
169
  toJSONSchema,
145
170
  toolHelpModel,
171
+ toolSearchPageSchema,
172
+ toolSearchRequestSchema,
146
173
  toolSearchSnapshotDigest,
147
174
  toolsToHelpModel,
175
+ treeJsonSchema,
148
176
  union,
149
177
  unknown,
150
178
  url,
151
179
  validatePath,
152
180
  virtualizeTools
153
- } from "./chunk-YB2FLNWI.js";
181
+ } from "./chunk-RVWZN3CI.js";
154
182
 
155
183
  // src/config.ts
156
184
  var DEFAULT_PORT = 8787;
157
- var DEFAULT_MAX_HOPS = 4;
158
185
  var DEFAULT_DEVICE_RECLAIM_SEC = 24 * 60 * 60;
159
186
  var DEFAULT_STORE_CLEANUP_INTERVAL_SEC = 15 * 60;
160
- function positiveIntEnv(value) {
161
- const n = Number(value);
162
- return Number.isFinite(n) && n > 0 ? Math.floor(n) : void 0;
163
- }
164
- function presignTtlEnv(value) {
165
- const ttl = positiveIntEnv(value);
166
- return ttl === void 0 ? void 0 : Math.min(ttl, PRESIGN_TTL_SEC_MAX);
167
- }
168
- function portEnv(value) {
169
- if (value === void 0 || value === "") return void 0;
170
- const n = Number(value);
171
- return Number.isInteger(n) && n >= 0 && n <= 65535 ? n : void 0;
172
- }
173
187
  function configFromEnv(env = process.env) {
174
- const allowInsecure = env.TB_ALLOW_INSECURE_HTTP === "true";
175
- const allowlist = (env.TB_REMOTE_ALLOWLIST ?? "").split(",").map((s) => s.trim()).filter((s) => s.length > 0);
188
+ const runtime = parseRuntimeEnv(env);
176
189
  const config = {
190
+ ...runtime,
177
191
  // TB_PORT 优先,PORT 兜底:Railway / Fly / Cloud Run / CF Container 等 PaaS 只注入
178
192
  // PORT,不认识 TB_PORT —— 不兜底的话容器会监听 8787 而平台探活另一个端口,部署直接失败。
179
- port: portEnv(env.TB_PORT) ?? portEnv(env.PORT) ?? DEFAULT_PORT,
193
+ port: parsePortEnv(env.TB_PORT) ?? parsePortEnv(env.PORT) ?? DEFAULT_PORT,
180
194
  host: env.TB_HOST !== void 0 && env.TB_HOST.length > 0 ? env.TB_HOST : "0.0.0.0",
181
195
  dataDir: env.TB_DATA_DIR !== void 0 && env.TB_DATA_DIR.length > 0 ? env.TB_DATA_DIR : "./data",
182
- allowInsecureHttp: allowInsecure,
183
196
  allowInsecureBootstrap: env.TB_ALLOW_INSECURE_BOOTSTRAP === "true",
184
- remote: {
185
- allowlist,
186
- maxHops: positiveIntEnv(env.TB_MAX_HOPS) ?? DEFAULT_MAX_HOPS,
187
- ...env.TB_INSTANCE_ID !== void 0 && env.TB_INSTANCE_ID.length > 0 ? { instanceId: env.TB_INSTANCE_ID } : {},
188
- allowInsecure
189
- },
190
- deviceReclaimSec: positiveIntEnv(env.TB_DEVICE_RECLAIM_SEC) ?? DEFAULT_DEVICE_RECLAIM_SEC,
191
- storeCleanupIntervalSec: positiveIntEnv(env.TB_STORE_CLEANUP_INTERVAL_SEC) ?? DEFAULT_STORE_CLEANUP_INTERVAL_SEC,
192
- // 0 合法(立即关停,本地/单机默认);positiveIntEnv 拒 0,故单独解析。
193
- shutdownDrainSec: (() => {
194
- const n = Number(env.TB_SHUTDOWN_DRAIN_SEC);
195
- return Number.isInteger(n) && n >= 0 ? n : 0;
196
- })()
197
+ deviceReclaimSec: runtime.deviceReclaimSec ?? DEFAULT_DEVICE_RECLAIM_SEC,
198
+ storeCleanupIntervalSec: runtime.storeCleanupIntervalSec ?? DEFAULT_STORE_CLEANUP_INTERVAL_SEC,
199
+ // 0 合法(立即关停,本地/单机默认)
200
+ shutdownDrainSec: parseNonNegativeIntEnv(env.TB_SHUTDOWN_DRAIN_SEC) ?? 0
197
201
  };
198
202
  if (env.TB_UI_DIR !== void 0 && env.TB_UI_DIR.length > 0) config.uiDir = env.TB_UI_DIR;
199
203
  if (env.TB_DATABASE_URL !== void 0 && env.TB_DATABASE_URL.length > 0) {
@@ -230,47 +234,9 @@ function configFromEnv(env = process.env) {
230
234
  if (env.TB_BOOTSTRAP_ADMIN_SK !== void 0 && env.TB_BOOTSTRAP_ADMIN_SK.length > 0) {
231
235
  config.adminSk = env.TB_BOOTSTRAP_ADMIN_SK;
232
236
  }
233
- const canonicalOrigin = normalizeCanonicalOrigin(env.TB_CANONICAL_ORIGIN);
234
- if (canonicalOrigin !== void 0) config.canonicalOrigin = canonicalOrigin;
235
237
  if (env.TB_SECRET_ENCRYPTION_KEY !== void 0 && env.TB_SECRET_ENCRYPTION_KEY.length > 0) {
236
238
  config.encryptionKey = env.TB_SECRET_ENCRYPTION_KEY;
237
239
  }
238
- const ttl = positiveIntEnv(env.TB_TOOL_CACHE_TTL);
239
- if (ttl !== void 0) config.toolCacheTtlSec = ttl;
240
- const refThreshold = positiveIntEnv(env.TB_REF_THRESHOLD_BYTES);
241
- if (refThreshold !== void 0) config.refThresholdBytes = refThreshold;
242
- const refTtl = presignTtlEnv(env.TB_REF_TTL_SEC);
243
- if (refTtl !== void 0) config.refTtlSec = refTtl;
244
- const uploadGrantTtl = presignTtlEnv(env.TB_UPLOAD_GRANT_TTL_SEC);
245
- if (uploadGrantTtl !== void 0) config.uploadGrantTtlSec = uploadGrantTtl;
246
- const storeMaxObjectBytes = positiveIntEnv(env.TB_STORE_MAX_OBJECT_BYTES);
247
- if (storeMaxObjectBytes !== void 0) config.storeMaxObjectBytes = storeMaxObjectBytes;
248
- const storeRelayMaxBytes = positiveIntEnv(env.TB_STORE_RELAY_MAX_BYTES);
249
- if (storeRelayMaxBytes !== void 0) config.storeRelayMaxBytes = storeRelayMaxBytes;
250
- const storeUploadTtlSec = presignTtlEnv(env.TB_STORE_UPLOAD_TTL_SEC);
251
- if (storeUploadTtlSec !== void 0) config.storeUploadTtlSec = storeUploadTtlSec;
252
- const storeShareTtlSec = presignTtlEnv(env.TB_STORE_SHARE_TTL_SEC);
253
- if (storeShareTtlSec !== void 0) config.storeShareTtlSec = storeShareTtlSec;
254
- const storeReadTtlSec = presignTtlEnv(env.TB_STORE_READ_TTL_SEC);
255
- if (storeReadTtlSec !== void 0) config.storeReadTtlSec = storeReadTtlSec;
256
- const storeCallMaxBytes = positiveIntEnv(env.TB_STORE_CALL_MAX_BYTES);
257
- if (storeCallMaxBytes !== void 0) config.storeCallMaxBytes = storeCallMaxBytes;
258
- const storeCallMaxObjectBytes = positiveIntEnv(env.TB_STORE_CALL_MAX_OBJECT_BYTES);
259
- if (storeCallMaxObjectBytes !== void 0) {
260
- config.storeCallMaxObjectBytes = storeCallMaxObjectBytes;
261
- }
262
- const storeCallMaxObjects = positiveIntEnv(env.TB_STORE_CALL_MAX_OBJECTS);
263
- if (storeCallMaxObjects !== void 0) config.storeCallMaxObjects = storeCallMaxObjects;
264
- const storeCallAllowedContentTypes = (env.TB_STORE_CALL_ALLOWED_CONTENT_TYPES ?? "").split(",").map((value) => value.trim()).filter((value) => value.length > 0);
265
- if (storeCallAllowedContentTypes.length > 0) {
266
- config.storeCallAllowedContentTypes = storeCallAllowedContentTypes;
267
- }
268
- if (env.TB_STORE_TOKEN_SECRET !== void 0 && env.TB_STORE_TOKEN_SECRET.length > 0) {
269
- if (env.TB_STORE_TOKEN_SECRET.length < 16) {
270
- throw new Error("TB_STORE_TOKEN_SECRET \u81F3\u5C11\u9700\u8981 16 \u4E2A\u5B57\u7B26");
271
- }
272
- config.storeTokenSecret = env.TB_STORE_TOKEN_SECRET;
273
- }
274
240
  return config;
275
241
  }
276
242
 
@@ -607,6 +573,48 @@ async function presignS3Put(client, url2, ttlSec, opts) {
607
573
  return { method: "PUT", url: signed.url, headers };
608
574
  }
609
575
 
576
+ // ../app/src/objectBodyStream.ts
577
+ function toWebObjectBodyStream(source, options = {}) {
578
+ const reader = source.getReader();
579
+ let released = false;
580
+ const release = () => {
581
+ if (released) return;
582
+ released = true;
583
+ reader.releaseLock();
584
+ };
585
+ const strategy = options.highWaterMark === void 0 ? void 0 : { highWaterMark: options.highWaterMark };
586
+ return new ReadableStream({
587
+ async pull(controller) {
588
+ try {
589
+ const { done, value } = await reader.read();
590
+ if (done) {
591
+ release();
592
+ controller.close();
593
+ } else if (value !== void 0) {
594
+ controller.enqueue(value);
595
+ }
596
+ } catch (error) {
597
+ try {
598
+ release();
599
+ } catch {
600
+ }
601
+ controller.error(error);
602
+ }
603
+ },
604
+ async cancel(reason) {
605
+ try {
606
+ if (reader.cancel !== void 0) await reader.cancel(reason);
607
+ else await source.cancel?.(reason);
608
+ } finally {
609
+ try {
610
+ release();
611
+ } catch {
612
+ }
613
+ }
614
+ }
615
+ }, strategy);
616
+ }
617
+
610
618
  // ../app/src/providers/s3Object.ts
611
619
  var META_HEADER_PREFIX = "x-amz-meta-";
612
620
  function stripEtagQuotes(etag) {
@@ -637,16 +645,12 @@ function createS3ObjectStore(cfg, opts) {
637
645
  const secErr = assertSecureUrl(cfg.endpoint, opts.allowInsecure);
638
646
  if (secErr) throw secErr;
639
647
  const client = new AwsClient({
640
- accessKeyId: cfg.accessKeyId,
641
- secretAccessKey: cfg.secretAccessKey,
642
- service: "s3",
643
- region: cfg.region ?? "auto"
644
- });
645
- const putClient = new AwsClient({
646
648
  accessKeyId: cfg.accessKeyId,
647
649
  secretAccessKey: cfg.secretAccessKey,
648
650
  service: "s3",
649
651
  region: cfg.region ?? "auto",
652
+ // Store 的重试由上层按操作幂等性统一决定。传输层不得自动重放写入,
653
+ // 也不能让读/删路径悄悄继承 aws4fetch 的默认 10 次重试。
650
654
  retries: 0
651
655
  });
652
656
  const base = cfg.endpoint.replace(/\/+$/, "");
@@ -670,38 +674,7 @@ function createS3ObjectStore(cfg, opts) {
670
674
  if (body instanceof Uint8Array) {
671
675
  return body.buffer instanceof ArrayBuffer ? new Uint8Array(body.buffer, body.byteOffset, body.byteLength) : new Uint8Array(body);
672
676
  }
673
- const source = body;
674
- const reader = source.getReader();
675
- return new ReadableStream({
676
- async pull(controller) {
677
- try {
678
- const chunk = await reader.read();
679
- if (chunk.done) {
680
- reader.releaseLock();
681
- controller.close();
682
- } else if (chunk.value !== void 0) {
683
- controller.enqueue(chunk.value);
684
- }
685
- } catch (error) {
686
- try {
687
- reader.releaseLock();
688
- } catch {
689
- }
690
- controller.error(error);
691
- }
692
- },
693
- async cancel(reason) {
694
- try {
695
- if (reader.cancel !== void 0) await reader.cancel(reason);
696
- else await source.cancel?.(reason);
697
- } finally {
698
- try {
699
- reader.releaseLock();
700
- } catch {
701
- }
702
- }
703
- }
704
- }, { highWaterMark: 0 });
677
+ return toWebObjectBodyStream(body, { highWaterMark: 0 });
705
678
  };
706
679
  const metaFromHeaders = (key, headers) => {
707
680
  const metadata = {};
@@ -750,7 +723,7 @@ function createS3ObjectStore(cfg, opts) {
750
723
  }
751
724
  if (putOpts?.ifMatchEtag !== void 0) headers["if-match"] = `"${putOpts.ifMatchEtag}"`;
752
725
  if (putOpts?.ifNoneMatch !== void 0) headers["if-none-match"] = putOpts.ifNoneMatch;
753
- const resp = await s3FetchWith(putClient, urlFor(key), {
726
+ const resp = await s3Fetch(urlFor(key), {
754
727
  method: "PUT",
755
728
  headers,
756
729
  body: fetchBody(body)
@@ -1256,8 +1229,8 @@ async function defaultStoreRuntime(deps) {
1256
1229
  service: new StoreService(deps.state, objects, serviceOptions(deps, tokenSecret))
1257
1230
  };
1258
1231
  }
1259
- function requestOrigin(runtime, deps) {
1260
- const raw = deps.canonicalOrigin ?? runtime?.requestOrigin;
1232
+ function resolveStoreRequestOrigin(rawRequestOrigin, canonicalOrigin) {
1233
+ const raw = rawRequestOrigin ?? canonicalOrigin;
1261
1234
  if (raw === void 0) {
1262
1235
  throw new TBError("unavailable", "request origin is unavailable", { retryable: false });
1263
1236
  }
@@ -1270,11 +1243,26 @@ function requestOrigin(runtime, deps) {
1270
1243
  if (url2.protocol !== "https:" && url2.protocol !== "http:" || url2.username !== "" || url2.password !== "") {
1271
1244
  throw new TBError("unavailable", "request origin is invalid", { retryable: false });
1272
1245
  }
1246
+ if (rawRequestOrigin !== void 0 && canonicalOrigin !== void 0) {
1247
+ let canonical;
1248
+ try {
1249
+ canonical = new URL(canonicalOrigin);
1250
+ } catch {
1251
+ throw new TBError("unavailable", "canonical origin is invalid", { retryable: false });
1252
+ }
1253
+ if (canonical.protocol !== "https:" && canonical.protocol !== "http:" || canonical.username !== "" || canonical.password !== "") {
1254
+ throw new TBError("unavailable", "canonical origin is invalid", { retryable: false });
1255
+ }
1256
+ url2.protocol = canonical.protocol;
1257
+ }
1273
1258
  return url2.origin;
1274
1259
  }
1275
- function storeUploadGrant(start, origin2) {
1260
+ function requestOrigin(runtime, deps) {
1261
+ return resolveStoreRequestOrigin(runtime?.requestOrigin, deps.canonicalOrigin);
1262
+ }
1263
+ function storeUploadGrant(start, origin) {
1276
1264
  const useRelay = start.alreadyCompleted || start.signedRequest === void 0;
1277
- const url2 = useRelay ? `${origin2}/~store/uploads/${encodeURIComponent(start.uploadId)}` : start.signedRequest.url;
1265
+ const url2 = useRelay ? `${origin}/~store/uploads/${encodeURIComponent(start.uploadId)}` : start.signedRequest.url;
1278
1266
  const headers = useRelay ? { [STORE_UPLOAD_HEADER]: start.uploadToken } : start.signedRequest.headers;
1279
1267
  return {
1280
1268
  uploadId: start.uploadId,
@@ -1369,10 +1357,10 @@ function lazyDefaultStoreModule(deps) {
1369
1357
  }
1370
1358
  };
1371
1359
  }
1372
- async function beginCapabilityUpload(deps, input, capabilityToken, origin2) {
1360
+ async function beginCapabilityUpload(deps, input, capabilityToken, origin) {
1373
1361
  const store = await defaultStoreRuntime(deps);
1374
1362
  const start = await store.service.beginCallUpload(input, capabilityToken);
1375
- return storeUploadGrant(start, origin2);
1363
+ return storeUploadGrant(start, origin);
1376
1364
  }
1377
1365
  async function completeCapabilityUpload(deps, uploadId2, uploadToken) {
1378
1366
  return await (await defaultStoreRuntime(deps)).service.completeUploadWithToken(
@@ -1400,37 +1388,7 @@ async function relayStoreUpload(deps, uploadId2, uploadToken, body) {
1400
1388
  async function storeObjectResponse(objects, object2) {
1401
1389
  const got = await objects.get(object2.driverKey);
1402
1390
  if (got === null) throw TBError.notFound("not found");
1403
- const reader = got.body.getReader();
1404
- const body = new ReadableStream({
1405
- async pull(controller) {
1406
- try {
1407
- const chunk = await reader.read();
1408
- if (chunk.done) {
1409
- reader.releaseLock();
1410
- controller.close();
1411
- } else if (chunk.value !== void 0) {
1412
- controller.enqueue(chunk.value);
1413
- }
1414
- } catch (error) {
1415
- try {
1416
- reader.releaseLock();
1417
- } catch {
1418
- }
1419
- controller.error(error);
1420
- }
1421
- },
1422
- async cancel(reason) {
1423
- try {
1424
- if (reader.cancel !== void 0) await reader.cancel(reason);
1425
- else await got.body.cancel?.(reason);
1426
- } finally {
1427
- try {
1428
- reader.releaseLock();
1429
- } catch {
1430
- }
1431
- }
1432
- }
1433
- });
1391
+ const body = toWebObjectBodyStream(got.body);
1434
1392
  return new Response(body, {
1435
1393
  headers: {
1436
1394
  "content-type": object2.contentType,
@@ -1502,7 +1460,6 @@ function cleanupProgress(value) {
1502
1460
  "objects",
1503
1461
  "shares",
1504
1462
  "callCapabilities",
1505
- "driverObjects",
1506
1463
  "idempotencyBindings"
1507
1464
  ]) {
1508
1465
  const cursor = cursors[field];
@@ -1516,7 +1473,6 @@ function emptyCleanupResult() {
1516
1473
  return {
1517
1474
  abandonedObjects: 0,
1518
1475
  deletedBytes: 0,
1519
- deletedOrphans: 0,
1520
1476
  deletedStaging: 0,
1521
1477
  expiredCallCapabilities: 0,
1522
1478
  expiredIdempotencyBindings: 0,
@@ -1527,7 +1483,6 @@ function emptyCleanupResult() {
1527
1483
  function addCleanupResult(target, page) {
1528
1484
  target.abandonedObjects += page.abandonedObjects;
1529
1485
  target.deletedBytes += page.deletedBytes;
1530
- target.deletedOrphans += page.deletedOrphans;
1531
1486
  target.deletedStaging += page.deletedStaging;
1532
1487
  target.expiredCallCapabilities += page.expiredCallCapabilities;
1533
1488
  target.expiredIdempotencyBindings += page.expiredIdempotencyBindings;
@@ -5804,8 +5759,8 @@ var LADDER_ERROR_HTTP_STATUS = {
5804
5759
  function parseSchema(schema, data) {
5805
5760
  return safeParse(schema, data);
5806
5761
  }
5807
- function shapeKeys(schemas) {
5808
- return new Set(schemas.flatMap((schema) => Object.keys(schema.shape)));
5762
+ function shapeKeys(schemas2) {
5763
+ return new Set(schemas2.flatMap((schema) => Object.keys(schema.shape)));
5809
5764
  }
5810
5765
  function isStandardSchema(schema) {
5811
5766
  if (schema == null) return false;
@@ -10980,14 +10935,14 @@ var require_core$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
10980
10935
  }
10981
10936
  return metaSchema;
10982
10937
  }
10983
- _removeAllSchemas(schemas, regex3) {
10984
- for (const keyRef in schemas) {
10985
- const sch = schemas[keyRef];
10938
+ _removeAllSchemas(schemas2, regex3) {
10939
+ for (const keyRef in schemas2) {
10940
+ const sch = schemas2[keyRef];
10986
10941
  if (!regex3 || regex3.test(keyRef)) {
10987
- if (typeof sch == "string") delete schemas[keyRef];
10942
+ if (typeof sch == "string") delete schemas2[keyRef];
10988
10943
  else if (sch && !sch.meta) {
10989
10944
  this._cache.delete(sch.schema);
10990
- delete schemas[keyRef];
10945
+ delete schemas2[keyRef];
10991
10946
  }
10992
10947
  }
10993
10948
  }
@@ -19288,8 +19243,8 @@ var GatewayMcpOAuthProvider = class {
19288
19243
  }
19289
19244
  get redirectUrl() {
19290
19245
  if (this.opts.redirectUri !== void 0) return this.opts.redirectUri;
19291
- const origin2 = this.opts.origin ?? "https://tool-bridge.invalid";
19292
- return `${origin2}${OAUTH_CALLBACK_PATH}`;
19246
+ const origin = this.opts.origin ?? "https://tool-bridge.invalid";
19247
+ return `${origin}${OAUTH_CALLBACK_PATH}`;
19293
19248
  }
19294
19249
  get clientMetadata() {
19295
19250
  return {
@@ -19738,15 +19693,6 @@ async function clientCredential(secrets, authRef) {
19738
19693
  ...values.clientSecret === void 0 ? {} : { clientSecret: values.clientSecret }
19739
19694
  };
19740
19695
  }
19741
- function parseTokenErrorMessage(payload) {
19742
- if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return void 0;
19743
- const record2 = payload;
19744
- for (const key of ["error_description", "error", "msg", "message"]) {
19745
- const value = record2[key];
19746
- if (typeof value === "string" && value !== "") return value;
19747
- }
19748
- return void 0;
19749
- }
19750
19696
  async function writeTokens(store, nodePath, next, previous) {
19751
19697
  const merged = {
19752
19698
  ...next,
@@ -19770,10 +19716,10 @@ async function requestTokens(opts) {
19770
19716
  let response;
19771
19717
  try {
19772
19718
  response = await opts.fetcher(endpoint, { method: "POST", headers, body });
19773
- } catch (err) {
19719
+ } catch {
19774
19720
  throw new TBError(
19775
19721
  "unavailable",
19776
- `\u4EE4\u724C\u7AEF\u70B9\u4E0D\u53EF\u8FBE:${err instanceof Error ? err.message : String(err)}`,
19722
+ "\u4EE4\u724C\u7AEF\u70B9\u4E0D\u53EF\u8FBE",
19777
19723
  { retryable: true }
19778
19724
  );
19779
19725
  }
@@ -19785,14 +19731,20 @@ async function requestTokens(opts) {
19785
19731
  payload = null;
19786
19732
  }
19787
19733
  if (!response.ok) {
19788
- const parsed = payload === null ? void 0 : parseTokenErrorMessage(payload);
19789
- const detail = parsed ?? `HTTP ${response.status}`;
19734
+ const detail = `HTTP ${response.status}`;
19790
19735
  if (response.status >= 500) {
19791
19736
  throw new TBError("unavailable", `\u4EE4\u724C\u7AEF\u70B9\u8FD4\u56DE ${detail}`, { retryable: true });
19792
19737
  }
19793
19738
  throw new TBError("invalid_argument", `\u4EE4\u724C\u7AEF\u70B9\u62D2\u7EDD\u4E86\u8BF7\u6C42:${detail}`);
19794
19739
  }
19795
- return parseTokenResponse(payload, opts.config, opts.now);
19740
+ try {
19741
+ return parseTokenResponse(payload, opts.config, opts.now);
19742
+ } catch (err) {
19743
+ if (isTBError(err) && err.code === "invalid_argument") {
19744
+ throw new TBError("invalid_argument", "\u4EE4\u724C\u7AEF\u70B9\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94");
19745
+ }
19746
+ throw err;
19747
+ }
19796
19748
  }
19797
19749
  function base64url(bytes) {
19798
19750
  let binary = "";
@@ -19804,7 +19756,14 @@ async function createPkce() {
19804
19756
  const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
19805
19757
  return { verifier, challenge: base64url(new Uint8Array(digest)) };
19806
19758
  }
19759
+ function requireProviderOAuthFetch(fetcher) {
19760
+ if (fetcher === void 0) {
19761
+ throw new TBError("unavailable", "Provider OAuth \u51FA\u7AD9\u901A\u9053\u672A\u914D\u7F6E", { retryable: false });
19762
+ }
19763
+ return fetcher;
19764
+ }
19807
19765
  async function startProviderAuthorization(opts) {
19766
+ const fetcher = requireProviderOAuthFetch(opts.fetcher);
19808
19767
  const existing = await readTokens(opts.store, opts.nodePath);
19809
19768
  if (existing !== void 0 && !shouldRefresh(existing, opts.now)) {
19810
19769
  return { status: "authorized" };
@@ -19814,7 +19773,7 @@ async function startProviderAuthorization(opts) {
19814
19773
  const client2 = await clientCredential(opts.secrets, opts.authRef);
19815
19774
  const refreshed = await requestTokens({
19816
19775
  config: opts.config,
19817
- fetcher: opts.fetcher,
19776
+ fetcher,
19818
19777
  now: opts.now,
19819
19778
  grant: { refreshToken: existing.refreshToken },
19820
19779
  ...client2
@@ -19847,10 +19806,11 @@ async function startProviderAuthorization(opts) {
19847
19806
  };
19848
19807
  }
19849
19808
  async function finishProviderAuthorization(opts) {
19809
+ const fetcher = requireProviderOAuthFetch(opts.fetcher);
19850
19810
  const client = await clientCredential(opts.secrets, opts.authRef);
19851
19811
  const tokens = await requestTokens({
19852
19812
  config: opts.config,
19853
- fetcher: opts.fetcher,
19813
+ fetcher,
19854
19814
  now: opts.now,
19855
19815
  grant: { code: opts.code, redirectUri: opts.origin + PROVIDER_OAUTH_CALLBACK_PATH },
19856
19816
  ...opts.codeVerifier === "" ? {} : { codeVerifier: opts.codeVerifier },
@@ -19859,6 +19819,7 @@ async function finishProviderAuthorization(opts) {
19859
19819
  await writeTokens(opts.store, opts.nodePath, tokens);
19860
19820
  }
19861
19821
  async function resolveProviderAccessToken(opts) {
19822
+ const fetcher = requireProviderOAuthFetch(opts.fetcher);
19862
19823
  const tokens = await readTokens(opts.store, opts.nodePath);
19863
19824
  if (tokens === void 0) throw providerReauthorizeRequired(opts.nodePath);
19864
19825
  if (opts.force !== true && !shouldRefresh(tokens, opts.now)) return tokens.accessToken;
@@ -19868,7 +19829,7 @@ async function resolveProviderAccessToken(opts) {
19868
19829
  try {
19869
19830
  refreshed = await requestTokens({
19870
19831
  config: opts.config,
19871
- fetcher: opts.fetcher,
19832
+ fetcher,
19872
19833
  now: opts.now,
19873
19834
  grant: { refreshToken: tokens.refreshToken },
19874
19835
  ...client
@@ -19972,7 +19933,7 @@ async function providerAccessTokenFor(opts) {
19972
19933
  config: opts.config,
19973
19934
  encryptionKey,
19974
19935
  ...opts.force === true ? { force: true } : {},
19975
- fetcher: fetch,
19936
+ fetcher: opts.deps.providerOAuthFetch,
19976
19937
  nodePath: opts.nodePath,
19977
19938
  now: /* @__PURE__ */ new Date(),
19978
19939
  // 调用期不需要 origin(只在构造授权 URL 时用);传空串会被 buildAuthorizationUrl 用到,
@@ -20313,11 +20274,11 @@ async function contextProviderFor(node, cfg, deps, requestUrl) {
20313
20274
  if (deps.refTtlSec !== void 0) opts.presignTtlSec = deps.refTtlSec;
20314
20275
  const encKey = deps.encryptionKey;
20315
20276
  if (encKey !== void 0) {
20316
- const origin2 = new URL(requestUrl).origin;
20277
+ const origin = new URL(requestUrl).origin;
20317
20278
  const relayTtlSec = deps.refTtlSec ?? PRESIGN_TTL_SEC_DEFAULT;
20318
20279
  opts.relayRefUrl = async (key) => {
20319
20280
  const exp = Math.floor(Date.now() / 1e3) + relayTtlSec;
20320
- return `${origin2}/~ref/${await signRefToken({ p: node.path, k: key, exp }, encKey)}`;
20281
+ return `${origin}/~ref/${await signRefToken({ p: node.path, k: key, exp }, encKey)}`;
20321
20282
  };
20322
20283
  }
20323
20284
  return createObjectContextProvider(objects, opts);
@@ -20338,69 +20299,20 @@ async function skillhubProviderFor(node, cfg, deps, requestUrl) {
20338
20299
  if (deps.refTtlSec !== void 0) opts.presignTtlSec = deps.refTtlSec;
20339
20300
  const encKey = deps.encryptionKey;
20340
20301
  if (encKey !== void 0) {
20341
- const origin2 = new URL(requestUrl).origin;
20302
+ const origin = new URL(requestUrl).origin;
20342
20303
  const relayTtlSec = deps.refTtlSec ?? PRESIGN_TTL_SEC_DEFAULT;
20343
20304
  opts.relayRefUrl = async (key) => {
20344
20305
  const exp = Math.floor(Date.now() / 1e3) + relayTtlSec;
20345
- return `${origin2}/~ref/${await signRefToken({ p: node.path, k: key, exp }, encKey)}`;
20306
+ return `${origin}/~ref/${await signRefToken({ p: node.path, k: key, exp }, encKey)}`;
20346
20307
  };
20347
20308
  }
20348
20309
  return createSkillhubProvider(objects, opts);
20349
20310
  }
20350
- async function dispatchSkillhubCmd(provider, command, args) {
20351
- switch (command.toLowerCase()) {
20352
- case "list":
20353
- return await provider.list(args.opts);
20354
- case "get":
20355
- return typeof args.file === "string" ? await provider.get_file(args.id, args.file) : await provider.get(args.id);
20356
- case "search":
20357
- return await provider.search(args.query, args.opts);
20358
- case "publish":
20359
- if (!Array.isArray(args.files)) {
20360
- throw new TBError("invalid_argument", "publish \u9700\u8981\u6570\u7EC4 'files'");
20361
- }
20362
- return await provider.publish({
20363
- ...typeof args.id === "string" ? { id: args.id } : {},
20364
- files: args.files
20365
- });
20366
- case "remove":
20367
- return await provider.remove(args.id);
20368
- default:
20369
- throw new TBError("invalid_argument", `unknown cmd '${command}'`);
20370
- }
20371
- }
20372
- async function dispatchContextCmd(provider, command, args) {
20373
- const unimplemented = () => {
20374
- throw new TBError("invalid_argument", `unknown cmd '${command}'(provider \u672A\u5B9E\u73B0)`);
20375
- };
20376
- switch (command.toLowerCase()) {
20377
- case "list":
20378
- if (provider.list === void 0) return unimplemented();
20379
- return await provider.list(args.path ?? "", args.opts);
20380
- case "get":
20381
- if (provider.get === void 0) return unimplemented();
20382
- return await provider.get(args.path);
20383
- case "write":
20384
- if (provider.write === void 0) return unimplemented();
20385
- if (typeof args.entry !== "object" || args.entry === null) {
20386
- throw new TBError("invalid_argument", "write \u9700\u8981\u5BF9\u8C61 'entry'");
20387
- }
20388
- return await provider.write(args.path, args.entry);
20389
- case "update":
20390
- if (provider.update === void 0) return unimplemented();
20391
- if (typeof args.patch !== "object" || args.patch === null) {
20392
- throw new TBError("invalid_argument", "update \u9700\u8981\u5BF9\u8C61 'patch'");
20393
- }
20394
- return await provider.update(args.path, args.patch);
20395
- case "delete":
20396
- if (provider.delete === void 0) return unimplemented();
20397
- return await provider.delete(args.path);
20398
- case "search":
20399
- if (provider.search === void 0) return unimplemented();
20400
- return await provider.search(args.query, args.opts);
20401
- default:
20402
- throw new TBError("invalid_argument", `unknown cmd '${command}'`);
20403
- }
20311
+ async function dispatchSkillhubCmd2(provider, command, args) {
20312
+ return await dispatchSkillhubCmd(provider, command, args);
20313
+ }
20314
+ async function dispatchContextCmd2(provider, command, args) {
20315
+ return await dispatchContextCmd(provider, command, args);
20404
20316
  }
20405
20317
  async function assertContextAlive(node, cfg, registry) {
20406
20318
  if (!isContextExpired(node.createdAt, cfg.ttl, Date.now())) return;
@@ -23845,8 +23757,8 @@ var LADDER_ERROR_HTTP_STATUS2 = {
23845
23757
  [ProtocolErrorCode2.MissingRequiredClientCapability]: 400,
23846
23758
  [HEADER_MISMATCH_ERROR_CODE2]: 400
23847
23759
  };
23848
- function httpStatusForErrorCode(code, origin2) {
23849
- if (origin2 === "in-band") return code === ProtocolErrorCode2.MissingRequiredClientCapability ? 400 : 200;
23760
+ function httpStatusForErrorCode(code, origin) {
23761
+ if (origin === "in-band") return code === ProtocolErrorCode2.MissingRequiredClientCapability ? 400 : 200;
23850
23762
  return LADDER_ERROR_HTTP_STATUS2[code] ?? 400;
23851
23763
  }
23852
23764
  function rejection(rung, cell, httpStatus, error, settled) {
@@ -24059,8 +23971,8 @@ function modernOnlyStrictRejection(route, supportedVersions) {
24059
23971
  function parseSchema2(schema, data) {
24060
23972
  return safeParse(schema, data);
24061
23973
  }
24062
- function shapeKeys2(schemas) {
24063
- return new Set(schemas.flatMap((schema) => Object.keys(schema.shape)));
23974
+ function shapeKeys2(schemas2) {
23975
+ return new Set(schemas2.flatMap((schema) => Object.keys(schema.shape)));
24064
23976
  }
24065
23977
  function isStandardSchema2(schema) {
24066
23978
  if (schema == null) return false;
@@ -29157,14 +29069,14 @@ var require_core$32 = /* @__PURE__ */ __commonJSMin2(((exports) => {
29157
29069
  }
29158
29070
  return metaSchema;
29159
29071
  }
29160
- _removeAllSchemas(schemas, regex3) {
29161
- for (const keyRef in schemas) {
29162
- const sch = schemas[keyRef];
29072
+ _removeAllSchemas(schemas2, regex3) {
29073
+ for (const keyRef in schemas2) {
29074
+ const sch = schemas2[keyRef];
29163
29075
  if (!regex3 || regex3.test(keyRef)) {
29164
- if (typeof sch == "string") delete schemas[keyRef];
29076
+ if (typeof sch == "string") delete schemas2[keyRef];
29165
29077
  else if (sch && !sch.meta) {
29166
29078
  this._cache.delete(sch.schema);
29167
- delete schemas[keyRef];
29079
+ delete schemas2[keyRef];
29168
29080
  }
29169
29081
  }
29170
29082
  }
@@ -36523,6 +36435,273 @@ async function passthroughRemote(opts) {
36523
36435
  // ../app/src/tbApp.ts
36524
36436
  import { Hono } from "hono";
36525
36437
 
36438
+ // ../core/src/protocol/openapi.ts
36439
+ var schemaRegistry = external_exports.registry();
36440
+ var schemas = {
36441
+ Error: tbErrorBodySchema,
36442
+ FeedbackDetail: feedbackDetailSchema,
36443
+ FeedbackList: feedbackListSchema,
36444
+ FeedbackRemoveResponse: feedbackRemoveResponseSchema,
36445
+ FeedbackSubmitRequest: feedbackSubmitRequestSchema,
36446
+ FeedbackSubmitResponse: feedbackSubmitResponseSchema,
36447
+ FeedbackView: feedbackViewSchema,
36448
+ FeedbackVoteRequest: feedbackVoteRequestSchema,
36449
+ Health: healthResponseSchema,
36450
+ Help: helpJsonSchema,
36451
+ Liveness: livenessResponseSchema,
36452
+ NodeInput: nodeInputSchema,
36453
+ OAuthAuthorizeRequest: oauthAuthorizeRequestSchema,
36454
+ OAuthAuthorizeResponse: oauthAuthorizeResponseSchema,
36455
+ Readiness: readinessResponseSchema,
36456
+ RegistryNode: registryNodeSchema,
36457
+ SearchRequest: toolSearchRequestSchema,
36458
+ SearchResponse: toolSearchPageSchema,
36459
+ Tree: treeJsonSchema
36460
+ };
36461
+ for (const [id, schema] of Object.entries(schemas)) schemaRegistry.add(schema, { id });
36462
+ function asOpenApiSchema(value) {
36463
+ if (Array.isArray(value)) return value.map(asOpenApiSchema);
36464
+ if (value === null || typeof value !== "object") return value;
36465
+ const out = {};
36466
+ for (const [key, entry] of Object.entries(value)) {
36467
+ if (key === "$schema") continue;
36468
+ if (key === "$ref" && typeof entry === "string" && !entry.startsWith("#/")) {
36469
+ out[key] = `#/components/schemas/${entry}`;
36470
+ } else {
36471
+ out[key] = asOpenApiSchema(entry);
36472
+ }
36473
+ }
36474
+ return out;
36475
+ }
36476
+ var generated = external_exports.toJSONSchema(schemaRegistry);
36477
+ var componentSchemas = Object.fromEntries(
36478
+ Object.entries(generated.schemas).map(([name, schema]) => [name, asOpenApiSchema(schema)])
36479
+ );
36480
+ var jsonContent = (schema) => ({
36481
+ "application/json": { schema: { $ref: `#/components/schemas/${schema}` } }
36482
+ });
36483
+ var jsonResponse = (description, schema) => ({
36484
+ description,
36485
+ content: jsonContent(schema)
36486
+ });
36487
+ var errorResponses = {
36488
+ 400: jsonResponse("Invalid request", "Error"),
36489
+ 401: jsonResponse("Unauthenticated", "Error"),
36490
+ 403: jsonResponse("Permission denied", "Error"),
36491
+ 404: jsonResponse("Not found or not visible", "Error"),
36492
+ 409: jsonResponse("Conflict", "Error"),
36493
+ 429: jsonResponse("Rate limited", "Error"),
36494
+ 500: jsonResponse("Internal error", "Error"),
36495
+ 503: jsonResponse("Unavailable", "Error")
36496
+ };
36497
+ var bearerSecurity = [{ bearerAuth: [] }];
36498
+ var pathParameter = {
36499
+ in: "path",
36500
+ name: "path",
36501
+ required: true,
36502
+ description: "Slash-delimited Tool Bridge tree path; each segment is URL encoded.",
36503
+ schema: { type: "string" }
36504
+ };
36505
+ var fixedControlPlaneOpenApi = {
36506
+ openapi: "3.1.0",
36507
+ info: {
36508
+ title: "Tool Bridge fixed control plane",
36509
+ version: "1.0.0"
36510
+ },
36511
+ components: {
36512
+ securitySchemes: {
36513
+ bearerAuth: { type: "http", scheme: "bearer" }
36514
+ },
36515
+ schemas: componentSchemas
36516
+ },
36517
+ paths: {
36518
+ "/healthz": {
36519
+ get: {
36520
+ operationId: "getHealth",
36521
+ security: [],
36522
+ responses: { 200: jsonResponse("Deployment health", "Health") }
36523
+ }
36524
+ },
36525
+ "/livez": {
36526
+ get: {
36527
+ operationId: "getLiveness",
36528
+ security: [],
36529
+ responses: { 200: jsonResponse("Process liveness", "Liveness") }
36530
+ }
36531
+ },
36532
+ "/readyz": {
36533
+ get: {
36534
+ operationId: "getReadiness",
36535
+ security: [],
36536
+ responses: {
36537
+ 200: jsonResponse("Ready", "Readiness"),
36538
+ 503: jsonResponse("Not ready", "Readiness")
36539
+ }
36540
+ }
36541
+ },
36542
+ "/~help": {
36543
+ get: {
36544
+ operationId: "getRootHelp",
36545
+ security: bearerSecurity,
36546
+ parameters: [{
36547
+ in: "query",
36548
+ name: "schemas",
36549
+ schema: { type: "string", enum: ["1"] }
36550
+ }],
36551
+ responses: { 200: jsonResponse("Root HTBP help", "Help"), ...errorResponses }
36552
+ }
36553
+ },
36554
+ "/{path}/~help": {
36555
+ get: {
36556
+ "operationId": "getHelp",
36557
+ "security": bearerSecurity,
36558
+ "parameters": [pathParameter, {
36559
+ in: "query",
36560
+ name: "schemas",
36561
+ schema: { type: "string", enum: ["1"] }
36562
+ }],
36563
+ "responses": { 200: jsonResponse("HTBP help", "Help"), ...errorResponses },
36564
+ "x-tool-bridge-greedy-path": true
36565
+ }
36566
+ },
36567
+ "/~tree": {
36568
+ get: {
36569
+ operationId: "getRootTree",
36570
+ security: bearerSecurity,
36571
+ parameters: [{ in: "query", name: "depth", schema: { type: "integer", minimum: 1, maximum: 8 } }],
36572
+ responses: { 200: jsonResponse("Root tree", "Tree"), ...errorResponses }
36573
+ }
36574
+ },
36575
+ "/{path}/~tree": {
36576
+ get: {
36577
+ "operationId": "getTree",
36578
+ "security": bearerSecurity,
36579
+ "parameters": [pathParameter, {
36580
+ in: "query",
36581
+ name: "depth",
36582
+ schema: { type: "integer", minimum: 1, maximum: 8 }
36583
+ }],
36584
+ "responses": { 200: jsonResponse("Subtree", "Tree"), ...errorResponses },
36585
+ "x-tool-bridge-greedy-path": true
36586
+ }
36587
+ },
36588
+ "/~search": {
36589
+ post: {
36590
+ operationId: "searchTools",
36591
+ security: bearerSecurity,
36592
+ requestBody: { required: true, content: jsonContent("SearchRequest") },
36593
+ responses: { 200: jsonResponse("Visible tool page", "SearchResponse"), ...errorResponses }
36594
+ }
36595
+ },
36596
+ "/{path}/~authorize": {
36597
+ post: {
36598
+ "operationId": "startOAuthAuthorization",
36599
+ "security": bearerSecurity,
36600
+ "parameters": [pathParameter],
36601
+ "requestBody": { required: false, content: jsonContent("OAuthAuthorizeRequest") },
36602
+ "responses": {
36603
+ 200: jsonResponse("Authorization status or redirect", "OAuthAuthorizeResponse"),
36604
+ ...errorResponses
36605
+ },
36606
+ "x-tool-bridge-greedy-path": true
36607
+ }
36608
+ },
36609
+ "/{path}/~register": {
36610
+ post: {
36611
+ "operationId": "registerNode",
36612
+ "security": bearerSecurity,
36613
+ "parameters": [pathParameter],
36614
+ "requestBody": { required: true, content: jsonContent("NodeInput") },
36615
+ "responses": {
36616
+ 200: jsonResponse("Registered node", "RegistryNode"),
36617
+ ...errorResponses
36618
+ },
36619
+ "x-tool-bridge-greedy-path": true
36620
+ }
36621
+ },
36622
+ "/{path}/~feedback": {
36623
+ get: {
36624
+ "operationId": "listFeedback",
36625
+ "security": bearerSecurity,
36626
+ "parameters": [pathParameter, {
36627
+ in: "query",
36628
+ name: "hidden",
36629
+ schema: { type: "string", enum: ["1"] }
36630
+ }],
36631
+ "responses": { 200: jsonResponse("Feedback list", "FeedbackList"), ...errorResponses },
36632
+ "x-tool-bridge-greedy-path": true
36633
+ },
36634
+ post: {
36635
+ "operationId": "submitFeedback",
36636
+ "security": bearerSecurity,
36637
+ "parameters": [pathParameter],
36638
+ "requestBody": { required: true, content: jsonContent("FeedbackSubmitRequest") },
36639
+ "responses": {
36640
+ 200: jsonResponse("Submitted feedback", "FeedbackSubmitResponse"),
36641
+ ...errorResponses
36642
+ },
36643
+ "x-tool-bridge-greedy-path": true
36644
+ }
36645
+ },
36646
+ "/{path}/~feedback/{id}": {
36647
+ get: {
36648
+ "operationId": "getFeedback",
36649
+ "security": bearerSecurity,
36650
+ "parameters": [pathParameter, { in: "path", name: "id", required: true, schema: { type: "string" } }],
36651
+ "responses": { 200: jsonResponse("Feedback detail", "FeedbackDetail"), ...errorResponses },
36652
+ "x-tool-bridge-greedy-path": true
36653
+ },
36654
+ post: {
36655
+ "operationId": "voteFeedback",
36656
+ "security": bearerSecurity,
36657
+ "parameters": [pathParameter, { in: "path", name: "id", required: true, schema: { type: "string" } }],
36658
+ "requestBody": { required: true, content: jsonContent("FeedbackVoteRequest") },
36659
+ "responses": { 200: jsonResponse("Updated feedback", "FeedbackView"), ...errorResponses },
36660
+ "x-tool-bridge-greedy-path": true
36661
+ },
36662
+ delete: {
36663
+ "operationId": "removeFeedback",
36664
+ "security": bearerSecurity,
36665
+ "parameters": [pathParameter, { in: "path", name: "id", required: true, schema: { type: "string" } }],
36666
+ "responses": {
36667
+ 200: jsonResponse("Feedback removed", "FeedbackRemoveResponse"),
36668
+ ...errorResponses
36669
+ },
36670
+ "x-tool-bridge-greedy-path": true
36671
+ }
36672
+ },
36673
+ "/{commandPath}": {
36674
+ post: {
36675
+ "operationId": "invoke",
36676
+ "security": bearerSecurity,
36677
+ "parameters": [{
36678
+ in: "path",
36679
+ name: "commandPath",
36680
+ required: true,
36681
+ schema: { type: "string" },
36682
+ description: "Complete HTBP command path, including the command/tool leaf."
36683
+ }],
36684
+ "requestBody": {
36685
+ required: true,
36686
+ description: "Raw command arguments; there is no {tool, arguments} envelope.",
36687
+ content: { "application/json": { schema: {} } }
36688
+ },
36689
+ "responses": {
36690
+ 200: {
36691
+ description: "Raw JSON or Markdown according to Accept.",
36692
+ content: {
36693
+ "application/json": { schema: {} },
36694
+ "text/markdown": { schema: { type: "string" } }
36695
+ }
36696
+ },
36697
+ ...errorResponses
36698
+ },
36699
+ "x-tool-bridge-greedy-path": true
36700
+ }
36701
+ }
36702
+ }
36703
+ };
36704
+
36526
36705
  // ../app/src/paths.ts
36527
36706
  function scopeForCmd(mod, nodePath, cmd) {
36528
36707
  return mod.help(nodePath).cmds.find((c) => c.name === cmd);
@@ -36606,7 +36785,9 @@ function indexByParent(nodes) {
36606
36785
  }
36607
36786
 
36608
36787
  // ../app/src/routes/feedback.ts
36609
- var feedbackJson = (value) => new Response(JSON.stringify(value), { headers: { "content-type": contentTypeFor("json") } });
36788
+ var feedbackJson = (schema, value) => new Response(JSON.stringify(schema.parse(value)), {
36789
+ headers: { "content-type": contentTypeFor("json") }
36790
+ });
36610
36791
  async function handleFeedbackGet(c) {
36611
36792
  const target = splitFeedback(new URL(c.req.url).pathname);
36612
36793
  if (target === null || target.path === "") throw TBError.notFound("no such path");
@@ -36615,7 +36796,7 @@ async function handleFeedbackGet(c) {
36615
36796
  const fb = new FeedbackStore(c.get("store"));
36616
36797
  if (target.id !== void 0) {
36617
36798
  const e = await fb.get(target.path, target.id);
36618
- return feedbackJson({
36799
+ return feedbackJson(feedbackDetailSchema, {
36619
36800
  id: e.id,
36620
36801
  path: target.path,
36621
36802
  title: e.title,
@@ -36629,7 +36810,7 @@ async function handleFeedbackGet(c) {
36629
36810
  }
36630
36811
  const views = await fb.listViews(target.path);
36631
36812
  const items = c.req.query("hidden") === "1" ? views : views.filter((v) => v.score > FEEDBACK_HIDE_SCORE);
36632
- return feedbackJson({ items });
36813
+ return feedbackJson(feedbackListSchema, { items });
36633
36814
  }
36634
36815
  async function handleFeedbackPost(c, env) {
36635
36816
  const { searchSync } = env;
@@ -36651,23 +36832,32 @@ async function handleFeedbackPost(c, env) {
36651
36832
  await searchSync?.reconcileNodeQuietly(path, { feedback: entries, marker });
36652
36833
  });
36653
36834
  if (target.id !== void 0) {
36654
- const vote = body.vote;
36655
- if (vote !== "up" && vote !== "down" && vote !== "clear") {
36835
+ const input2 = feedbackVoteRequestSchema.safeParse(body);
36836
+ if (!input2.success) {
36656
36837
  throw new TBError("invalid_argument", `body.vote must be 'up' | 'down' | 'clear'`);
36657
36838
  }
36658
- return feedbackJson(await fb.vote(target.path, target.id, ctx.owner, vote));
36839
+ return feedbackJson(
36840
+ feedbackViewSchema,
36841
+ await fb.vote(target.path, target.id, ctx.owner, input2.data.vote)
36842
+ );
36659
36843
  }
36660
- if (typeof body.title !== "string" || typeof body.detail !== "string") {
36844
+ const input = feedbackSubmitRequestSchema.safeParse(body);
36845
+ if (!input.success) {
36661
36846
  throw new TBError("invalid_argument", "body must be { title: string, detail: string }");
36662
36847
  }
36663
36848
  await new NodeRegistryStore(store).resolve(target.path);
36664
36849
  const entry = await fb.submit(
36665
36850
  target.path,
36666
- { title: body.title, detail: body.detail },
36851
+ input.data,
36667
36852
  ctx.owner,
36668
36853
  (/* @__PURE__ */ new Date()).toISOString()
36669
36854
  );
36670
- return feedbackJson({ id: entry.id, path: target.path, title: entry.title, at: entry.at });
36855
+ return feedbackJson(feedbackSubmitResponseSchema, {
36856
+ id: entry.id,
36857
+ path: target.path,
36858
+ title: entry.title,
36859
+ at: entry.at
36860
+ });
36671
36861
  } catch (error) {
36672
36862
  await searchSync?.abort(marker);
36673
36863
  throw error;
@@ -36693,12 +36883,12 @@ async function handleFeedbackDelete(c, env) {
36693
36883
  await searchSync?.abort(marker);
36694
36884
  throw error;
36695
36885
  }
36696
- return feedbackJson({ ok: true });
36886
+ return feedbackJson(feedbackRemoveResponseSchema, { ok: true });
36697
36887
  }
36698
36888
 
36699
36889
  // ../app/src/responses.ts
36700
36890
  function tbErrorResponse(err) {
36701
- return new Response(JSON.stringify(err.toJSON()), {
36891
+ return new Response(JSON.stringify(tbErrorBodySchema.parse(err.toJSON())), {
36702
36892
  status: err.httpStatus,
36703
36893
  headers: { "content-type": "application/json; charset=utf-8" }
36704
36894
  });
@@ -36735,7 +36925,7 @@ async function runHandler(fn) {
36735
36925
  }
36736
36926
  function renderHelp(model, rep) {
36737
36927
  if (rep === "json") {
36738
- return new Response(JSON.stringify(renderHelpJson(model)), {
36928
+ return new Response(JSON.stringify(helpJsonSchema.parse(renderHelpJson(model))), {
36739
36929
  headers: { "content-type": contentTypeFor("json") }
36740
36930
  });
36741
36931
  }
@@ -36939,14 +37129,14 @@ async function authorizeToolNode(c, env, node, encryptionKey) {
36939
37129
  authRef: config.authRef,
36940
37130
  config: exported.oauth,
36941
37131
  encryptionKey,
36942
- fetcher: fetch,
37132
+ fetcher: deps.providerOAuthFetch,
36943
37133
  nodePath: node.path,
36944
37134
  now: /* @__PURE__ */ new Date(),
36945
37135
  origin: deps.canonicalOrigin ?? new URL(c.req.url).origin,
36946
37136
  secrets: deps.secrets,
36947
37137
  store: deps.state
36948
37138
  });
36949
- return new Response(JSON.stringify(result), {
37139
+ return new Response(JSON.stringify(oauthAuthorizeResponseSchema.parse(result)), {
36950
37140
  headers: { "content-type": contentTypeFor("json") }
36951
37141
  });
36952
37142
  }
@@ -36993,7 +37183,7 @@ async function handleRegister(c, env) {
36993
37183
  await invalidateProviderOAuth(store, body.path);
36994
37184
  await searchSync?.reconcileNodeQuietly(body.path, { marker });
36995
37185
  if (await refreshDynamicSearchNode(node, ctx, deps)) await searchSync?.abort(marker);
36996
- return new Response(JSON.stringify(node), {
37186
+ return new Response(JSON.stringify(registryNodeSchema.parse(node)), {
36997
37187
  headers: { "content-type": contentTypeFor("json") }
36998
37188
  });
36999
37189
  }
@@ -37020,6 +37210,11 @@ async function handleAuthorize(c, env) {
37020
37210
  } catch {
37021
37211
  throw TBError.notFound("not found");
37022
37212
  }
37213
+ const rawBody = await c.req.json().catch(() => ({}));
37214
+ const body = oauthAuthorizeRequestSchema.safeParse(rawBody);
37215
+ if (!body.success) {
37216
+ throw new TBError("invalid_argument", "body only accepts optional redirectUri string");
37217
+ }
37023
37218
  if (node.kind === "tool" && node.config?.kind === "tool") {
37024
37219
  return await authorizeToolNode(c, env, node, encKey);
37025
37220
  }
@@ -37029,8 +37224,7 @@ async function handleAuthorize(c, env) {
37029
37224
  `'${path}' \u65E2\u4E0D\u662F auth:'oauth' \u7684 mcp \u6302\u8F7D,\u4E5F\u4E0D\u662F\u58F0\u660E\u4E86 oauth \u7684 tool \u6302\u8F7D`
37030
37225
  );
37031
37226
  }
37032
- const body = await c.req.json().catch(() => null);
37033
- const redirectUri = body !== null && typeof body.redirectUri === "string" ? body.redirectUri : void 0;
37227
+ const redirectUri = body.data.redirectUri;
37034
37228
  const result = await startMcpAuthorization({
37035
37229
  store,
37036
37230
  encryptionKey: encKey,
@@ -37039,7 +37233,7 @@ async function handleAuthorize(c, env) {
37039
37233
  origin: deps.canonicalOrigin ?? new URL(c.req.url).origin,
37040
37234
  ...redirectUri !== void 0 ? { redirectUri } : {}
37041
37235
  });
37042
- return new Response(JSON.stringify(result), {
37236
+ return new Response(JSON.stringify(oauthAuthorizeResponseSchema.parse(result)), {
37043
37237
  headers: { "content-type": contentTypeFor("json") }
37044
37238
  });
37045
37239
  }
@@ -37141,16 +37335,6 @@ function uploadId(body) {
37141
37335
  }
37142
37336
  return body.uploadId;
37143
37337
  }
37144
- function origin(c, canonicalOrigin) {
37145
- let url2;
37146
- try {
37147
- url2 = new URL(canonicalOrigin ?? c.req.url);
37148
- } catch {
37149
- throw new TBError("unavailable", "request origin is invalid", { retryable: false });
37150
- }
37151
- if (url2.protocol !== "https:" && url2.protocol !== "http:" || url2.username !== "" || url2.password !== "") throw new TBError("unavailable", "request origin is invalid", { retryable: false });
37152
- return url2.origin;
37153
- }
37154
37338
  function registerStoreCapabilityRoutes(app, deps) {
37155
37339
  app.post("/system/store/create_upload", async (c, next) => {
37156
37340
  if (c.req.header(STORE_CALL_CAPABILITY_HEADER) === void 0) return await next();
@@ -37162,7 +37346,7 @@ function registerStoreCapabilityRoutes(app, deps) {
37162
37346
  deps,
37163
37347
  body,
37164
37348
  capability,
37165
- origin(c, deps.canonicalOrigin)
37349
+ resolveStoreRequestOrigin(c.req.url, deps.canonicalOrigin)
37166
37350
  );
37167
37351
  return c.json(result);
37168
37352
  });
@@ -37262,7 +37446,7 @@ async function finishToolAuthorization(opts) {
37262
37446
  codeVerifier: opts.verifier,
37263
37447
  config: exported.oauth,
37264
37448
  encryptionKey: opts.encryptionKey,
37265
- fetcher: fetch,
37449
+ fetcher: opts.deps.providerOAuthFetch,
37266
37450
  nodePath: opts.node.path,
37267
37451
  now: /* @__PURE__ */ new Date(),
37268
37452
  origin: opts.origin,
@@ -37279,21 +37463,23 @@ function registerPublicRoutes(app, env) {
37279
37463
  app.get("/healthz", async (c) => {
37280
37464
  const catalog = deps.pluginCatalog;
37281
37465
  const digest = await env.pluginCatalogDigest();
37282
- return c.json({
37466
+ return c.json(healthResponseSchema.parse({
37283
37467
  healthy: true,
37284
37468
  version: deps.version,
37285
37469
  ...catalog !== void 0 && digest !== void 0 ? { catalog: { count: Object.keys(catalog).length, digest } } : {}
37286
- });
37470
+ }));
37287
37471
  });
37288
- app.get("/livez", (c) => c.json({ live: true }));
37472
+ app.get("/livez", (c) => c.json(livenessResponseSchema.parse({ live: true })));
37289
37473
  app.get("/readyz", async (c) => {
37290
37474
  const probe = deps.readiness;
37291
- if (probe === void 0) return c.json({ checks: {}, ready: true });
37475
+ if (probe === void 0) {
37476
+ return c.json(readinessResponseSchema.parse({ checks: {}, ready: true }));
37477
+ }
37292
37478
  try {
37293
- const report = await probe();
37479
+ const report = readinessResponseSchema.parse(await probe());
37294
37480
  return c.json(report, report.ready ? 200 : 503);
37295
37481
  } catch {
37296
- return c.json({ checks: {}, ready: false }, 503);
37482
+ return c.json(readinessResponseSchema.parse({ checks: {}, ready: false }), 503);
37297
37483
  }
37298
37484
  });
37299
37485
  app.get(
@@ -37453,7 +37639,11 @@ function registerSearchRoute(app, env) {
37453
37639
  if (opts.cursor !== void 0 && typeof opts.cursor !== "string") {
37454
37640
  throw new TBError("invalid_argument", "opts.cursor must be a string");
37455
37641
  }
37456
- const query = body.query.trim();
37642
+ const wireRequest = toolSearchRequestSchema.parse({
37643
+ query: body.query,
37644
+ ...rawOpts === void 0 ? {} : { opts }
37645
+ });
37646
+ const query = wireRequest.query;
37457
37647
  await searchSync?.ensureReady();
37458
37648
  const ctx = c.get("ctx");
37459
37649
  const registry = new NodeRegistryStore(c.get("store"));
@@ -37531,7 +37721,7 @@ function registerSearchRoute(app, env) {
37531
37721
  }
37532
37722
  if (items.length === 0) responseCursor = void 0;
37533
37723
  const result = responseCursor === void 0 ? { items } : { items, cursor: responseCursor };
37534
- return new Response(JSON.stringify(result), {
37724
+ return new Response(JSON.stringify(toolSearchPageSchema.parse(result)), {
37535
37725
  headers: { "content-type": contentTypeFor("json") }
37536
37726
  });
37537
37727
  })
@@ -38102,27 +38292,27 @@ async function handleInvoke(c, env) {
38102
38292
  throw new TBError("permission_denied", `readOnly \u6302\u8F7D\u62D2\u7EDD '${command}'`);
38103
38293
  }
38104
38294
  if (directUpload) {
38105
- const result3 = await createContextUploadGrant(
38106
- node,
38107
- cfg,
38108
- deps,
38109
- args2
38295
+ const result3 = await dispatchContextUploadCmd(
38296
+ args2,
38297
+ (input) => createContextUploadGrant(node, cfg, deps, input)
38110
38298
  );
38111
38299
  return renderResult(result3, negotiate(c.req.header("accept")));
38112
38300
  }
38113
38301
  if (cfg.provider === "device-fs") {
38302
+ const forwardedArgs = parseContextCmdArgs(command, args2);
38114
38303
  const result3 = await invokeDevice(deps, deviceIdForDeviceFs(cfg), {
38115
38304
  path: `fs/${command}`,
38116
- arguments: args2,
38305
+ arguments: forwardedArgs,
38117
38306
  context: deviceCallContextFrom(ctx)
38118
38307
  });
38119
38308
  return renderResult(result3, negotiate(c.req.header("accept")));
38120
38309
  }
38121
38310
  const contextMarker = deviceMarkerOf(cfg.providerConfig);
38122
38311
  if (cfg.provider !== "r2" && cfg.provider !== "s3" && contextMarker !== null) {
38312
+ const forwardedArgs = parseContextCmdArgs(command, args2);
38123
38313
  const result3 = await invokeDevice(deps, contextMarker.deviceId, {
38124
38314
  path: `${relativeDevicePath(node.path, contextMarker.mountPath)}/${command}`,
38125
- arguments: args2,
38315
+ arguments: forwardedArgs,
38126
38316
  context: deviceCallContextFrom(ctx)
38127
38317
  });
38128
38318
  return renderResult(result3, negotiate(c.req.header("accept")));
@@ -38130,7 +38320,7 @@ async function handleInvoke(c, env) {
38130
38320
  if (cfg.provider !== "r2" && cfg.provider !== "s3") {
38131
38321
  const local = localContext(deps, node);
38132
38322
  if (local !== null) {
38133
- const result4 = await dispatchContextCmd(local, command, args2);
38323
+ const result4 = await dispatchContextCmd2(local, command, args2);
38134
38324
  return renderResult(result4, negotiate(c.req.header("accept")));
38135
38325
  }
38136
38326
  const { manifest, export: exported } = await requirePluginExport(
@@ -38150,11 +38340,11 @@ async function handleInvoke(c, env) {
38150
38340
  ...cfg.authRef !== void 0 ? { upstreamAuthRef: cfg.authRef } : {},
38151
38341
  ...deps.pluginBindings !== void 0 ? { bindings: deps.pluginBindings } : {}
38152
38342
  });
38153
- const result3 = await dispatchContextCmd(provider2, command, args2);
38343
+ const result3 = await dispatchContextCmd2(provider2, command, args2);
38154
38344
  return renderResult(result3, negotiate(c.req.header("accept")));
38155
38345
  }
38156
38346
  const provider = await contextProviderFor(node, cfg, deps, c.req.url);
38157
- const result2 = await dispatchContextCmd(provider, command, args2);
38347
+ const result2 = await dispatchContextCmd2(provider, command, args2);
38158
38348
  return renderResult(result2, negotiate(c.req.header("accept")));
38159
38349
  }
38160
38350
  if (node.kind === "skillhub" && node.config?.kind === "skillhub") {
@@ -38172,7 +38362,7 @@ async function handleInvoke(c, env) {
38172
38362
  throw new TBError("permission_denied", `readOnly \u6302\u8F7D\u62D2\u7EDD '${command}'`);
38173
38363
  }
38174
38364
  const provider = await skillhubProviderFor(node, cfg, deps, c.req.url);
38175
- const result2 = await dispatchSkillhubCmd(provider, command, args2);
38365
+ const result2 = await dispatchSkillhubCmd2(provider, command, args2);
38176
38366
  return renderResult(result2, negotiate(c.req.header("accept")));
38177
38367
  }
38178
38368
  if (node.kind !== "builtin" || node.config?.kind !== "builtin") {
@@ -38228,7 +38418,7 @@ async function handleInvoke(c, env) {
38228
38418
  let result;
38229
38419
  try {
38230
38420
  result = await mod.dispatch(cmd, args, ctx, {
38231
- requestOrigin: deps.canonicalOrigin ?? new URL(c.req.url).origin
38421
+ requestOrigin: resolveStoreRequestOrigin(c.req.url, deps.canonicalOrigin)
38232
38422
  });
38233
38423
  } catch (error) {
38234
38424
  await searchSync?.abort(registryMarker);
@@ -38340,7 +38530,7 @@ async function handleHelp(c, env) {
38340
38530
  if (remote) return remote;
38341
38531
  const builtins = builtinsOf(store);
38342
38532
  const refresh = c.req.query("refresh") === "1";
38343
- const schemas = c.req.query("schemas") === "1";
38533
+ const schemas2 = c.req.query("schemas") === "1";
38344
38534
  let node;
38345
38535
  try {
38346
38536
  node = await registry.get(path);
@@ -38349,14 +38539,14 @@ async function handleHelp(c, env) {
38349
38539
  if (toolModel !== null) return renderHelp(await enrichHelp(toolModel, path, store), rep);
38350
38540
  const cmdModel = await commandHelpModelFor(registry, ctx, builtins, deps, path, {
38351
38541
  refresh,
38352
- schemas
38542
+ schemas: schemas2
38353
38543
  });
38354
38544
  if (cmdModel !== null) return renderHelp(await enrichHelp(cmdModel, path, store), rep);
38355
38545
  throw TBError.notFound("not found");
38356
38546
  }
38357
38547
  const model = await helpModelFor(node, registry, ctx, builtins, deps, {
38358
38548
  refresh,
38359
- schemas,
38549
+ schemas: schemas2,
38360
38550
  now: (/* @__PURE__ */ new Date()).toISOString()
38361
38551
  });
38362
38552
  return renderHelp(await enrichHelp(model, path, store), rep);
@@ -38408,7 +38598,7 @@ async function handleTree(c, env) {
38408
38598
  });
38409
38599
  const rep = negotiate(c.req.header("accept"));
38410
38600
  if (rep === "json") {
38411
- return new Response(JSON.stringify(tree), {
38601
+ return new Response(JSON.stringify(treeJsonSchema.parse(tree)), {
38412
38602
  headers: { "content-type": contentTypeFor("json") }
38413
38603
  });
38414
38604
  }
@@ -39841,7 +40031,7 @@ import { join as join4 } from "path";
39841
40031
  // package.json
39842
40032
  var package_default = {
39843
40033
  name: "@tool-bridge/server",
39844
- version: "0.16.0",
40034
+ version: "0.17.0",
39845
40035
  description: "tool-bridge self-hosted server: run the HTBP gateway on Node with SQLite or PostgreSQL persistence, filesystem object storage and WebSocket device channel \u2014 single container via docker run",
39846
40036
  type: "module",
39847
40037
  license: "MIT",
@@ -40023,6 +40213,7 @@ function resolveUiAssets(uiDirOverride) {
40023
40213
  }
40024
40214
 
40025
40215
  // src/server.ts
40216
+ var providerOAuthFetch = createGuardedFetch({ crossOriginRedirect: "error" });
40026
40217
  function pgBackends(databaseUrl) {
40027
40218
  const sql = postgres(databaseUrl, { onnotice: () => {
40028
40219
  } });
@@ -40136,6 +40327,7 @@ function createTbServer(config) {
40136
40327
  const deps = {
40137
40328
  state,
40138
40329
  secrets,
40330
+ providerOAuthFetch,
40139
40331
  version: package_default.version,
40140
40332
  remote: config.remote,
40141
40333
  search,