skybridge 0.0.0-dev.db8be9c → 0.0.0-dev.dbab7df

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 (517) hide show
  1. package/README.md +155 -0
  2. package/bin/run.js +0 -4
  3. package/dist/cli/build-helpers.d.ts +11 -0
  4. package/dist/cli/build-helpers.js +107 -0
  5. package/dist/cli/build-helpers.js.map +1 -0
  6. package/dist/cli/build-helpers.test.js +132 -0
  7. package/dist/cli/build-helpers.test.js.map +1 -0
  8. package/dist/cli/build-steps.d.ts +2 -0
  9. package/dist/cli/build-steps.js +73 -0
  10. package/dist/cli/build-steps.js.map +1 -0
  11. package/dist/cli/build-steps.test.js +52 -0
  12. package/dist/cli/build-steps.test.js.map +1 -0
  13. package/dist/cli/detect-port.d.ts +18 -0
  14. package/dist/cli/detect-port.js +50 -0
  15. package/dist/cli/detect-port.js.map +1 -0
  16. package/dist/cli/header.d.ts +1 -1
  17. package/dist/cli/header.js +1 -1
  18. package/dist/cli/header.js.map +1 -1
  19. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  20. package/dist/cli/resolve-skybridge-config.js +18 -0
  21. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  22. package/dist/cli/run-command.js.map +1 -1
  23. package/dist/cli/run-plain.d.ts +18 -0
  24. package/dist/cli/run-plain.js +89 -0
  25. package/dist/cli/run-plain.js.map +1 -0
  26. package/dist/{hooks → cli}/telemetry.js +1 -3
  27. package/dist/cli/telemetry.js.map +1 -0
  28. package/dist/cli/tunnel-control-server.d.ts +9 -0
  29. package/dist/cli/tunnel-control-server.js +31 -0
  30. package/dist/cli/tunnel-control-server.js.map +1 -0
  31. package/dist/cli/tunnel-control-server.test.js +39 -0
  32. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  33. package/dist/cli/tunnel-handler.d.ts +3 -0
  34. package/dist/cli/tunnel-handler.js +48 -0
  35. package/dist/cli/tunnel-handler.js.map +1 -0
  36. package/dist/cli/tunnel-handler.test.js +105 -0
  37. package/dist/cli/tunnel-handler.test.js.map +1 -0
  38. package/dist/cli/tunnel.d.ts +57 -0
  39. package/dist/cli/tunnel.js +154 -0
  40. package/dist/cli/tunnel.js.map +1 -0
  41. package/dist/cli/tunnel.test.js +190 -0
  42. package/dist/cli/tunnel.test.js.map +1 -0
  43. package/dist/cli/types.d.ts +5 -0
  44. package/dist/cli/types.js +2 -0
  45. package/dist/cli/types.js.map +1 -0
  46. package/dist/cli/use-execute-steps.d.ts +2 -1
  47. package/dist/cli/use-execute-steps.js +6 -1
  48. package/dist/cli/use-execute-steps.js.map +1 -1
  49. package/dist/cli/use-messages.d.ts +3 -0
  50. package/dist/cli/use-messages.js +11 -0
  51. package/dist/cli/use-messages.js.map +1 -0
  52. package/dist/cli/use-nodemon.d.ts +16 -0
  53. package/dist/cli/use-nodemon.js +84 -0
  54. package/dist/cli/use-nodemon.js.map +1 -0
  55. package/dist/cli/use-open-browser.d.ts +1 -0
  56. package/dist/cli/use-open-browser.js +44 -0
  57. package/dist/cli/use-open-browser.js.map +1 -0
  58. package/dist/cli/use-tunnel.d.ts +14 -0
  59. package/dist/cli/use-tunnel.js +131 -0
  60. package/dist/cli/use-tunnel.js.map +1 -0
  61. package/dist/cli/use-typescript-check.d.ts +15 -0
  62. package/dist/cli/use-typescript-check.js +97 -0
  63. package/dist/cli/use-typescript-check.js.map +1 -0
  64. package/dist/commands/build.d.ts +0 -3
  65. package/dist/commands/build.js +3 -16
  66. package/dist/commands/build.js.map +1 -1
  67. package/dist/commands/create.d.ts +9 -0
  68. package/dist/commands/create.js +30 -0
  69. package/dist/commands/create.js.map +1 -0
  70. package/dist/commands/dev.d.ts +7 -1
  71. package/dist/commands/dev.js +117 -9
  72. package/dist/commands/dev.js.map +1 -1
  73. package/dist/commands/start.d.ts +3 -1
  74. package/dist/commands/start.js +37 -15
  75. package/dist/commands/start.js.map +1 -1
  76. package/dist/commands/telemetry/disable.js +4 -3
  77. package/dist/commands/telemetry/disable.js.map +1 -1
  78. package/dist/commands/telemetry/enable.js +3 -2
  79. package/dist/commands/telemetry/enable.js.map +1 -1
  80. package/dist/commands/telemetry/status.js +3 -2
  81. package/dist/commands/telemetry/status.js.map +1 -1
  82. package/dist/context-warnings.d.ts +5 -0
  83. package/dist/context-warnings.js +31 -0
  84. package/dist/context-warnings.js.map +1 -0
  85. package/dist/context-warnings.test.d.ts +1 -0
  86. package/dist/context-warnings.test.js +28 -0
  87. package/dist/context-warnings.test.js.map +1 -0
  88. package/dist/server/app.d.ts +180 -0
  89. package/dist/server/app.js +266 -0
  90. package/dist/server/app.js.map +1 -0
  91. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  92. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  93. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  94. package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
  95. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  96. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  97. package/dist/server/auth/discovery.d.ts +33 -0
  98. package/dist/server/auth/discovery.js +56 -0
  99. package/dist/server/auth/discovery.js.map +1 -0
  100. package/dist/server/auth/discovery.test.d.ts +1 -0
  101. package/dist/server/auth/discovery.test.js +93 -0
  102. package/dist/server/auth/discovery.test.js.map +1 -0
  103. package/dist/server/auth/index.d.ts +30 -0
  104. package/dist/server/auth/index.js +2 -0
  105. package/dist/server/auth/index.js.map +1 -0
  106. package/dist/server/auth/providers/auth0.d.ts +40 -0
  107. package/dist/server/auth/providers/auth0.js +31 -0
  108. package/dist/server/auth/providers/auth0.js.map +1 -0
  109. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  110. package/dist/server/auth/providers/auth0.test.js +50 -0
  111. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  112. package/dist/server/auth/providers/authplane.d.ts +49 -0
  113. package/dist/server/auth/providers/authplane.js +57 -0
  114. package/dist/server/auth/providers/authplane.js.map +1 -0
  115. package/dist/server/auth/providers/authplane.test.d.ts +1 -0
  116. package/dist/server/auth/providers/authplane.test.js +140 -0
  117. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  118. package/dist/server/auth/providers/clerk.d.ts +51 -0
  119. package/dist/server/auth/providers/clerk.js +19 -0
  120. package/dist/server/auth/providers/clerk.js.map +1 -0
  121. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  122. package/dist/server/auth/providers/clerk.test.js +30 -0
  123. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  124. package/dist/server/auth/providers/custom.d.ts +40 -0
  125. package/dist/server/auth/providers/custom.js +56 -0
  126. package/dist/server/auth/providers/custom.js.map +1 -0
  127. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  128. package/dist/server/auth/providers/custom.test.js +158 -0
  129. package/dist/server/auth/providers/custom.test.js.map +1 -0
  130. package/dist/server/auth/providers/descope.d.ts +44 -0
  131. package/dist/server/auth/providers/descope.js +44 -0
  132. package/dist/server/auth/providers/descope.js.map +1 -0
  133. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  134. package/dist/server/auth/providers/descope.test.js +62 -0
  135. package/dist/server/auth/providers/descope.test.js.map +1 -0
  136. package/dist/server/auth/providers/shared.d.ts +2 -0
  137. package/dist/server/auth/providers/shared.js +6 -0
  138. package/dist/server/auth/providers/shared.js.map +1 -0
  139. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  140. package/dist/server/auth/providers/shared.test.js +10 -0
  141. package/dist/server/auth/providers/shared.test.js.map +1 -0
  142. package/dist/server/auth/providers/stytch.d.ts +25 -0
  143. package/dist/server/auth/providers/stytch.js +16 -0
  144. package/dist/server/auth/providers/stytch.js.map +1 -0
  145. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  146. package/dist/server/auth/providers/verify-spy.js +21 -0
  147. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  148. package/dist/server/auth/providers/workos.d.ts +33 -0
  149. package/dist/server/auth/providers/workos.js +15 -0
  150. package/dist/server/auth/providers/workos.js.map +1 -0
  151. package/dist/server/auth/security-schemes.d.ts +23 -0
  152. package/dist/server/auth/security-schemes.js +64 -0
  153. package/dist/server/auth/security-schemes.js.map +1 -0
  154. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  155. package/dist/server/auth/security-schemes.test.js +99 -0
  156. package/dist/server/auth/security-schemes.test.js.map +1 -0
  157. package/dist/server/auth/setup.d.ts +6 -0
  158. package/dist/server/auth/setup.js +91 -0
  159. package/dist/server/auth/setup.js.map +1 -0
  160. package/dist/server/auth/setup.test.d.ts +1 -0
  161. package/dist/server/auth/setup.test.js +512 -0
  162. package/dist/server/auth/setup.test.js.map +1 -0
  163. package/dist/server/auth/verify.d.ts +46 -0
  164. package/dist/server/auth/verify.js +62 -0
  165. package/dist/server/auth/verify.js.map +1 -0
  166. package/dist/server/auth/verify.test.d.ts +1 -0
  167. package/dist/server/auth/verify.test.js +149 -0
  168. package/dist/server/auth/verify.test.js.map +1 -0
  169. package/dist/server/auth-extra.test-d.d.ts +1 -0
  170. package/dist/server/auth-extra.test-d.js +70 -0
  171. package/dist/server/auth-extra.test-d.js.map +1 -0
  172. package/dist/server/auth.d.ts +57 -0
  173. package/dist/server/auth.js +27 -0
  174. package/dist/server/auth.js.map +1 -0
  175. package/dist/server/build-manifest.test.d.ts +1 -0
  176. package/dist/server/build-manifest.test.js +28 -0
  177. package/dist/server/build-manifest.test.js.map +1 -0
  178. package/dist/server/content-helpers.d.ts +67 -0
  179. package/dist/server/content-helpers.js +79 -0
  180. package/dist/server/content-helpers.js.map +1 -0
  181. package/dist/server/content-helpers.test.d.ts +1 -0
  182. package/dist/server/content-helpers.test.js +70 -0
  183. package/dist/server/content-helpers.test.js.map +1 -0
  184. package/dist/server/express.d.ts +13 -0
  185. package/dist/server/express.js +77 -0
  186. package/dist/server/express.js.map +1 -0
  187. package/dist/server/express.test.d.ts +1 -0
  188. package/dist/server/express.test.js +519 -0
  189. package/dist/server/express.test.js.map +1 -0
  190. package/dist/server/file-ref.d.ts +28 -0
  191. package/dist/server/file-ref.js +27 -0
  192. package/dist/server/file-ref.js.map +1 -0
  193. package/dist/server/host.d.ts +2 -0
  194. package/dist/server/host.js +11 -0
  195. package/dist/server/host.js.map +1 -0
  196. package/dist/server/host.test.d.ts +1 -0
  197. package/dist/server/host.test.js +13 -0
  198. package/dist/server/host.test.js.map +1 -0
  199. package/dist/server/index.d.ts +21 -3
  200. package/dist/server/index.js +16 -2
  201. package/dist/server/index.js.map +1 -1
  202. package/dist/server/inferUtilityTypes.d.ts +6 -6
  203. package/dist/server/inferUtilityTypes.js.map +1 -1
  204. package/dist/server/mcp-errors.test.d.ts +1 -0
  205. package/dist/server/mcp-errors.test.js +37 -0
  206. package/dist/server/mcp-errors.test.js.map +1 -0
  207. package/dist/server/metric.d.ts +14 -0
  208. package/dist/server/metric.js +62 -0
  209. package/dist/server/metric.js.map +1 -0
  210. package/dist/server/middleware.d.ts +162 -0
  211. package/dist/server/middleware.js +126 -0
  212. package/dist/server/middleware.js.map +1 -0
  213. package/dist/server/middleware.test-d.d.ts +1 -0
  214. package/dist/server/middleware.test-d.js +75 -0
  215. package/dist/server/middleware.test-d.js.map +1 -0
  216. package/dist/server/middleware.test.d.ts +1 -0
  217. package/dist/server/middleware.test.js +559 -0
  218. package/dist/server/middleware.test.js.map +1 -0
  219. package/dist/server/register-tool.test.d.ts +1 -0
  220. package/dist/server/register-tool.test.js +23 -0
  221. package/dist/server/register-tool.test.js.map +1 -0
  222. package/dist/server/requestOrigin.d.ts +7 -0
  223. package/dist/server/requestOrigin.js +25 -0
  224. package/dist/server/requestOrigin.js.map +1 -0
  225. package/dist/server/server.d.ts +387 -65
  226. package/dist/server/server.js +532 -99
  227. package/dist/server/server.js.map +1 -1
  228. package/dist/server/skills-integration.test.d.ts +1 -0
  229. package/dist/server/skills-integration.test.js +79 -0
  230. package/dist/server/skills-integration.test.js.map +1 -0
  231. package/dist/server/skills.d.ts +27 -0
  232. package/dist/server/skills.js +188 -0
  233. package/dist/server/skills.js.map +1 -0
  234. package/dist/server/skills.test.d.ts +1 -0
  235. package/dist/server/skills.test.js +243 -0
  236. package/dist/server/skills.test.js.map +1 -0
  237. package/dist/server/templateHelper.d.ts +5 -7
  238. package/dist/server/templateHelper.js +3 -22
  239. package/dist/server/templateHelper.js.map +1 -1
  240. package/dist/server/templates.generated.d.ts +4 -0
  241. package/dist/server/templates.generated.js +47 -0
  242. package/dist/server/templates.generated.js.map +1 -0
  243. package/dist/server/tool-extra.test.d.ts +1 -0
  244. package/dist/server/tool-extra.test.js +72 -0
  245. package/dist/server/tool-extra.test.js.map +1 -0
  246. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  247. package/dist/server/tunnel-proxy-router.js +110 -0
  248. package/dist/server/tunnel-proxy-router.js.map +1 -0
  249. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  250. package/dist/server/tunnel-proxy-router.test.js +229 -0
  251. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  252. package/dist/server/view-name.test-d.d.ts +1 -0
  253. package/dist/server/view-name.test-d.js +8 -0
  254. package/dist/server/view-name.test-d.js.map +1 -0
  255. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  256. package/dist/server/view-resource-resolution.test.js +172 -0
  257. package/dist/server/view-resource-resolution.test.js.map +1 -0
  258. package/dist/server/viewsDevServer.d.ts +14 -0
  259. package/dist/server/viewsDevServer.js +48 -0
  260. package/dist/server/viewsDevServer.js.map +1 -0
  261. package/dist/standard-schema.d.ts +3 -0
  262. package/dist/standard-schema.js +2 -0
  263. package/dist/standard-schema.js.map +1 -0
  264. package/dist/test/utils.d.ts +21 -31
  265. package/dist/test/utils.js +55 -45
  266. package/dist/test/utils.js.map +1 -1
  267. package/dist/test/view.test.d.ts +1 -0
  268. package/dist/test/view.test.js +536 -0
  269. package/dist/test/view.test.js.map +1 -0
  270. package/dist/version.d.ts +1 -0
  271. package/dist/version.js +3 -0
  272. package/dist/version.js.map +1 -0
  273. package/dist/views/index.d.ts +3 -0
  274. package/dist/views/index.js +3 -0
  275. package/dist/views/index.js.map +1 -0
  276. package/dist/views/scan-views.d.ts +16 -0
  277. package/dist/views/scan-views.js +88 -0
  278. package/dist/views/scan-views.js.map +1 -0
  279. package/dist/views/scan-views.test.d.ts +1 -0
  280. package/dist/views/scan-views.test.js +99 -0
  281. package/dist/views/scan-views.test.js.map +1 -0
  282. package/dist/views/validate-view.d.ts +1 -0
  283. package/dist/views/validate-view.js +9 -0
  284. package/dist/views/validate-view.js.map +1 -0
  285. package/dist/views/validate-view.test.d.ts +1 -0
  286. package/dist/views/validate-view.test.js +24 -0
  287. package/dist/views/validate-view.test.js.map +1 -0
  288. package/dist/web/bridges/adaptor.d.ts +51 -0
  289. package/dist/web/bridges/adaptor.js +327 -0
  290. package/dist/web/bridges/adaptor.js.map +1 -0
  291. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  292. package/dist/web/bridges/adaptor.test.js +225 -0
  293. package/dist/web/bridges/adaptor.test.js.map +1 -0
  294. package/dist/web/bridges/apps-sdk/bridge.d.ts +7 -2
  295. package/dist/web/bridges/apps-sdk/bridge.js +15 -3
  296. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  297. package/dist/web/bridges/apps-sdk/index.d.ts +1 -2
  298. package/dist/web/bridges/apps-sdk/index.js +0 -1
  299. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  300. package/dist/web/bridges/apps-sdk/types.d.ts +38 -26
  301. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  302. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  303. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  304. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  305. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  306. package/dist/web/bridges/get-adaptor.js +9 -7
  307. package/dist/web/bridges/get-adaptor.js.map +1 -1
  308. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  309. package/dist/web/bridges/get-adaptor.test.js +32 -0
  310. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  311. package/dist/web/bridges/index.js.map +1 -1
  312. package/dist/web/bridges/mcp-app/bridge.d.ts +27 -31
  313. package/dist/web/bridges/mcp-app/bridge.js +111 -198
  314. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  315. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  316. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  317. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  318. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  319. package/dist/web/bridges/mcp-app/index.js +0 -1
  320. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  321. package/dist/web/bridges/mcp-app/types.d.ts +2 -0
  322. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  323. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +17 -3
  324. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +14 -2
  325. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  326. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -41
  327. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  328. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  329. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  330. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  331. package/dist/web/bridges/types.d.ts +160 -12
  332. package/dist/web/bridges/types.js +14 -1
  333. package/dist/web/bridges/types.js.map +1 -1
  334. package/dist/web/bridges/types.test.d.ts +1 -0
  335. package/dist/web/bridges/types.test.js +19 -0
  336. package/dist/web/bridges/types.test.js.map +1 -0
  337. package/dist/web/bridges/use-host-context.d.ts +5 -0
  338. package/dist/web/bridges/use-host-context.js +5 -0
  339. package/dist/web/bridges/use-host-context.js.map +1 -1
  340. package/dist/web/components/modal-provider.d.ts +4 -0
  341. package/dist/web/components/modal-provider.js +46 -0
  342. package/dist/web/components/modal-provider.js.map +1 -0
  343. package/dist/web/create-store.d.ts +26 -0
  344. package/dist/web/create-store.js +43 -3
  345. package/dist/web/create-store.js.map +1 -1
  346. package/dist/web/create-store.test.js +32 -26
  347. package/dist/web/create-store.test.js.map +1 -1
  348. package/dist/web/data-llm.d.ts +35 -2
  349. package/dist/web/data-llm.js +31 -3
  350. package/dist/web/data-llm.js.map +1 -1
  351. package/dist/web/data-llm.test.js +52 -36
  352. package/dist/web/data-llm.test.js.map +1 -1
  353. package/dist/web/generate-helpers.d.ts +32 -27
  354. package/dist/web/generate-helpers.js +29 -24
  355. package/dist/web/generate-helpers.js.map +1 -1
  356. package/dist/web/generate-helpers.test-d.js +33 -31
  357. package/dist/web/generate-helpers.test-d.js.map +1 -1
  358. package/dist/web/generate-helpers.test.js +2 -2
  359. package/dist/web/generate-helpers.test.js.map +1 -1
  360. package/dist/web/helpers/state.d.ts +2 -2
  361. package/dist/web/helpers/state.js +11 -11
  362. package/dist/web/helpers/state.js.map +1 -1
  363. package/dist/web/helpers/state.test.js +9 -9
  364. package/dist/web/helpers/state.test.js.map +1 -1
  365. package/dist/web/hooks/index.d.ts +9 -3
  366. package/dist/web/hooks/index.js +8 -2
  367. package/dist/web/hooks/index.js.map +1 -1
  368. package/dist/web/hooks/test/utils.d.ts +7 -2
  369. package/dist/web/hooks/test/utils.js +18 -3
  370. package/dist/web/hooks/test/utils.js.map +1 -1
  371. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  372. package/dist/web/hooks/use-call-tool.js +28 -0
  373. package/dist/web/hooks/use-call-tool.js.map +1 -1
  374. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  375. package/dist/web/hooks/use-call-tool.test.js +64 -29
  376. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  377. package/dist/web/hooks/use-display-mode.d.ts +23 -3
  378. package/dist/web/hooks/use-display-mode.js +20 -0
  379. package/dist/web/hooks/use-display-mode.js.map +1 -1
  380. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  381. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  382. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  383. package/dist/web/hooks/use-display-mode.test.js +57 -21
  384. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  385. package/dist/web/hooks/use-download.d.ts +3 -0
  386. package/dist/web/hooks/use-download.js +7 -0
  387. package/dist/web/hooks/use-download.js.map +1 -0
  388. package/dist/web/hooks/use-download.test.d.ts +1 -0
  389. package/dist/web/hooks/use-download.test.js +103 -0
  390. package/dist/web/hooks/use-download.test.js.map +1 -0
  391. package/dist/web/hooks/use-files.d.ts +35 -6
  392. package/dist/web/hooks/use-files.js +37 -2
  393. package/dist/web/hooks/use-files.js.map +1 -1
  394. package/dist/web/hooks/use-files.test.js +36 -3
  395. package/dist/web/hooks/use-files.test.js.map +1 -1
  396. package/dist/web/hooks/use-host.d.ts +22 -0
  397. package/dist/web/hooks/use-host.js +30 -0
  398. package/dist/web/hooks/use-host.js.map +1 -0
  399. package/dist/web/hooks/use-host.test.d.ts +1 -0
  400. package/dist/web/hooks/use-host.test.js +59 -0
  401. package/dist/web/hooks/use-host.test.js.map +1 -0
  402. package/dist/web/hooks/use-open-external.d.ts +20 -1
  403. package/dist/web/hooks/use-open-external.js +17 -1
  404. package/dist/web/hooks/use-open-external.js.map +1 -1
  405. package/dist/web/hooks/use-open-external.test.js +39 -14
  406. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  407. package/dist/web/hooks/use-register-view-tool.d.ts +37 -0
  408. package/dist/web/hooks/use-register-view-tool.js +50 -0
  409. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  410. package/dist/web/hooks/use-request-close.d.ts +16 -0
  411. package/dist/web/hooks/use-request-close.js +21 -0
  412. package/dist/web/hooks/use-request-close.js.map +1 -0
  413. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  414. package/dist/web/hooks/use-request-close.test.js +47 -0
  415. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  416. package/dist/web/hooks/use-request-modal.d.ts +18 -3
  417. package/dist/web/hooks/use-request-modal.js +25 -8
  418. package/dist/web/hooks/use-request-modal.js.map +1 -1
  419. package/dist/web/hooks/use-request-modal.test.js +16 -2
  420. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  421. package/dist/web/hooks/use-request-size.d.ts +20 -0
  422. package/dist/web/hooks/use-request-size.js +24 -0
  423. package/dist/web/hooks/use-request-size.js.map +1 -0
  424. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  425. package/dist/web/hooks/use-request-size.test.js +47 -0
  426. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  427. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  428. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  429. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  430. package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
  431. package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
  432. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
  433. package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
  434. package/dist/web/hooks/use-set-open-in-app-url.test.js +63 -0
  435. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
  436. package/dist/web/hooks/use-tool-info.d.ts +46 -14
  437. package/dist/web/hooks/use-tool-info.js +29 -7
  438. package/dist/web/hooks/use-tool-info.js.map +1 -1
  439. package/dist/web/hooks/use-tool-info.test-d.js +11 -34
  440. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  441. package/dist/web/hooks/use-tool-info.test.js +42 -37
  442. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  443. package/dist/web/hooks/use-user.d.ts +5 -2
  444. package/dist/web/hooks/use-user.js +23 -4
  445. package/dist/web/hooks/use-user.js.map +1 -1
  446. package/dist/web/hooks/use-user.test.js +104 -28
  447. package/dist/web/hooks/use-user.test.js.map +1 -1
  448. package/dist/web/hooks/use-view-state.d.ts +25 -0
  449. package/dist/web/hooks/use-view-state.js +42 -0
  450. package/dist/web/hooks/use-view-state.js.map +1 -0
  451. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  452. package/dist/web/hooks/use-view-state.test.js +212 -0
  453. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  454. package/dist/web/hooks/use-viewport.d.ts +20 -0
  455. package/dist/web/hooks/use-viewport.js +21 -0
  456. package/dist/web/hooks/use-viewport.js.map +1 -0
  457. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  458. package/dist/web/hooks/use-viewport.test.js +109 -0
  459. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  460. package/dist/web/index.d.ts +2 -2
  461. package/dist/web/index.js +1 -2
  462. package/dist/web/index.js.map +1 -1
  463. package/dist/web/mount-view.d.ts +21 -0
  464. package/dist/web/mount-view.js +47 -0
  465. package/dist/web/mount-view.js.map +1 -0
  466. package/dist/web/proxy.js +0 -1
  467. package/dist/web/proxy.js.map +1 -1
  468. package/dist/web/types.d.ts +4 -0
  469. package/dist/web/types.js.map +1 -1
  470. package/package.json +59 -33
  471. package/tsconfig.base.json +33 -0
  472. package/dist/commands/telemetry.d.ts +0 -9
  473. package/dist/commands/telemetry.js +0 -39
  474. package/dist/commands/telemetry.js.map +0 -1
  475. package/dist/hooks/telemetry.js.map +0 -1
  476. package/dist/server/templates/development.hbs +0 -66
  477. package/dist/server/templates/production.hbs +0 -7
  478. package/dist/server/widgetsDevServer.d.ts +0 -12
  479. package/dist/server/widgetsDevServer.js +0 -47
  480. package/dist/server/widgetsDevServer.js.map +0 -1
  481. package/dist/test/widget.test.js +0 -255
  482. package/dist/test/widget.test.js.map +0 -1
  483. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -14
  484. package/dist/web/bridges/apps-sdk/adaptor.js +0 -39
  485. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  486. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -19
  487. package/dist/web/bridges/mcp-app/adaptor.js +0 -145
  488. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  489. package/dist/web/hooks/use-layout.d.ts +0 -22
  490. package/dist/web/hooks/use-layout.js +0 -23
  491. package/dist/web/hooks/use-layout.js.map +0 -1
  492. package/dist/web/hooks/use-layout.test.js +0 -96
  493. package/dist/web/hooks/use-layout.test.js.map +0 -1
  494. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  495. package/dist/web/hooks/use-widget-state.js +0 -32
  496. package/dist/web/hooks/use-widget-state.js.map +0 -1
  497. package/dist/web/hooks/use-widget-state.test.js +0 -61
  498. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  499. package/dist/web/mount-widget.d.ts +0 -1
  500. package/dist/web/mount-widget.js +0 -19
  501. package/dist/web/mount-widget.js.map +0 -1
  502. package/dist/web/plugin/data-llm.test.js +0 -81
  503. package/dist/web/plugin/data-llm.test.js.map +0 -1
  504. package/dist/web/plugin/plugin.d.ts +0 -2
  505. package/dist/web/plugin/plugin.js +0 -39
  506. package/dist/web/plugin/plugin.js.map +0 -1
  507. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  508. package/dist/web/plugin/transform-data-llm.js +0 -96
  509. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  510. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  511. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  512. /package/dist/{test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  513. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  514. /package/dist/{hooks → cli}/telemetry.d.ts +0 -0
  515. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  516. /package/dist/{web/plugin/data-llm.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  517. /package/dist/{web/plugin/transform-data-llm.test.d.ts → cli/tunnel.test.d.ts} +0 -0
@@ -0,0 +1,519 @@
1
+ import http from "node:http";
2
+ import { Client, StreamableHTTPClientTransport, } from "@modelcontextprotocol/client";
3
+ import { afterEach, describe, expect, it, vi } from "vitest";
4
+ import { Skybridge } from "./app.js";
5
+ vi.mock("@skybridge/devtools", () => ({
6
+ devtoolsStaticServer: () => ((_req, _res, next) => next()),
7
+ }));
8
+ vi.mock("./viewsDevServer.js", () => ({
9
+ viewsDevServer: (_httpServer) => ((_req, _res, next) => next()),
10
+ }));
11
+ async function listen(app) {
12
+ const server = http.createServer(app);
13
+ await new Promise((resolve) => server.listen(0, resolve));
14
+ const port = server.address().port;
15
+ return { port, server };
16
+ }
17
+ let openServer;
18
+ afterEach(() => openServer?.close());
19
+ async function postMcp(port) {
20
+ return fetch(`http://localhost:${port}/mcp`, {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify({ jsonrpc: "2.0", method: "initialize", id: 1 }),
24
+ });
25
+ }
26
+ async function postApi(port) {
27
+ return fetch(`http://localhost:${port}/api/test`, { method: "POST" });
28
+ }
29
+ describe("Skybridge.express", () => {
30
+ it("exposes a ready Express app immediately after construction", () => {
31
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
32
+ expect(app.express).toBeDefined();
33
+ expect(typeof app.express.use).toBe("function");
34
+ expect(typeof app.express.get).toBe("function");
35
+ });
36
+ it("app.express.get registers a route reachable alongside /mcp", async () => {
37
+ const { createApp } = await import("./express.js");
38
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
39
+ app.express.get("/health", (_req, res) => {
40
+ res.json({ status: "ok" });
41
+ });
42
+ const httpServer = http.createServer();
43
+ await createApp({ app, httpServer });
44
+ const { port, server: listening } = await listen(app.express);
45
+ openServer = listening;
46
+ const health = await fetch(`http://localhost:${port}/health`);
47
+ expect(health.status).toBe(200);
48
+ expect(await health.json()).toEqual({ status: "ok" });
49
+ // /mcp still works (POST returns 200/4xx, not 404)
50
+ const mcp = await postMcp(port);
51
+ expect(mcp.status).not.toBe(404);
52
+ });
53
+ it("app.use and app.express.use produce the same registration order", async () => {
54
+ const { createApp } = await import("./express.js");
55
+ const callsA = [];
56
+ const callsB = [];
57
+ const buildApp = () => new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
58
+ const sA = buildApp();
59
+ sA.use((_req, _res, next) => {
60
+ callsA.push("first");
61
+ next();
62
+ });
63
+ sA.express.use((_req, _res, next) => {
64
+ callsA.push("second");
65
+ next();
66
+ });
67
+ const sB = buildApp();
68
+ sB.express.use((_req, _res, next) => {
69
+ callsB.push("first");
70
+ next();
71
+ });
72
+ sB.use((_req, _res, next) => {
73
+ callsB.push("second");
74
+ next();
75
+ });
76
+ for (const s of [sA, sB]) {
77
+ s.express.get("/probe", (_req, res) => res.json({ ok: true }));
78
+ const httpServer = http.createServer();
79
+ await createApp({ app: s, httpServer });
80
+ const { port, server: listening } = await listen(s.express);
81
+ openServer = listening;
82
+ await fetch(`http://localhost:${port}/probe`);
83
+ listening.close();
84
+ }
85
+ expect(callsA).toEqual(["first", "second"]);
86
+ expect(callsB).toEqual(["first", "second"]);
87
+ });
88
+ it("useOnError still wraps thrown /mcp errors after the route is mounted", async () => {
89
+ const { createApp } = await import("./express.js");
90
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
91
+ // Register the error handler BEFORE createApp — useOnError should still
92
+ // apply it after /mcp, so /mcp errors hit it.
93
+ const seen = [];
94
+ app.useOnError((_err, _req, res, _next) => {
95
+ seen.push("useOnError");
96
+ res.status(503).json({ from: "useOnError" });
97
+ });
98
+ // Force the /mcp handler to throw so the error pipeline runs.
99
+ app.use("/mcp", () => {
100
+ throw new Error("boom");
101
+ });
102
+ const httpServer = http.createServer();
103
+ await createApp({
104
+ app,
105
+ httpServer,
106
+ // Mirror what run() does: forward the app's useOnError handlers
107
+ // to createApp so they get applied after /mcp.
108
+ // biome-ignore lint/complexity/useLiteralKeys: test mirrors run() internals to verify useOnError ordering
109
+ errorMiddleware: app["errorMiddleware"],
110
+ });
111
+ const { port, server: listening } = await listen(app.express);
112
+ openServer = listening;
113
+ const res = await postMcp(port);
114
+ expect(seen).toEqual(["useOnError"]);
115
+ expect(res.status).toBe(503);
116
+ expect(await res.json()).toEqual({ from: "useOnError" });
117
+ });
118
+ });
119
+ describe("Skybridge JSON body parser options", () => {
120
+ const largeBody = JSON.stringify({ data: "x".repeat(200 * 1024) });
121
+ async function postEcho(port, body) {
122
+ return fetch(`http://localhost:${port}/echo`, {
123
+ method: "POST",
124
+ headers: { "Content-Type": "application/json" },
125
+ body,
126
+ });
127
+ }
128
+ it("forwards json options to express.json", async () => {
129
+ const app = new Skybridge({ name: "t", version: "0.0.0", json: { limit: "10mb" } }, (server) => server);
130
+ app.express.post("/echo", (req, res) => {
131
+ res.json({ received: req.body.data.length });
132
+ });
133
+ const { port, server: listening } = await listen(app.express);
134
+ openServer = listening;
135
+ const res = await postEcho(port, largeBody);
136
+ expect(res.status).toBe(200);
137
+ expect(await res.json()).toEqual({ received: 200 * 1024 });
138
+ });
139
+ it("keeps the default 100kb limit when no options are passed", async () => {
140
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
141
+ app.express.post("/echo", (_req, res) => {
142
+ res.json({ ok: true });
143
+ });
144
+ const { port, server: listening } = await listen(app.express);
145
+ openServer = listening;
146
+ const res = await postEcho(port, largeBody);
147
+ expect(res.status).toBe(413);
148
+ });
149
+ });
150
+ describe("createApp", () => {
151
+ it("runs global custom middleware before the /mcp handler", async () => {
152
+ const { createApp } = await import("./express.js");
153
+ const calls = [];
154
+ const mw = (_req, _res, next) => {
155
+ calls.push("custom");
156
+ next();
157
+ };
158
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
159
+ app.use(mw);
160
+ const httpServer = http.createServer();
161
+ const expressApp = await createApp({ app, httpServer });
162
+ const { port, server: httpListening } = await listen(expressApp);
163
+ openServer = httpListening;
164
+ await postMcp(port);
165
+ expect(calls).toEqual(["custom"]);
166
+ });
167
+ it("runs path-scoped middleware on /mcp", async () => {
168
+ const { createApp } = await import("./express.js");
169
+ const calls = [];
170
+ const mw = (_req, _res, next) => {
171
+ calls.push("auth");
172
+ next();
173
+ };
174
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
175
+ app.use("/mcp", mw);
176
+ const httpServer = http.createServer();
177
+ const expressApp = await createApp({ app, httpServer });
178
+ const { port, server: httpListening } = await listen(expressApp);
179
+ openServer = httpListening;
180
+ await postMcp(port);
181
+ expect(calls).toEqual(["auth"]);
182
+ });
183
+ it("allows middleware to short-circuit with 401", async () => {
184
+ const { createApp } = await import("./express.js");
185
+ const calls = [];
186
+ const reject = (_req, res) => {
187
+ calls.push("reject");
188
+ res.status(401).json({ error: "Unauthorized" });
189
+ };
190
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
191
+ app.use("/mcp", reject);
192
+ const httpServer = http.createServer();
193
+ const expressApp = await createApp({ app, httpServer });
194
+ const { port, server: httpListening } = await listen(expressApp);
195
+ openServer = httpListening;
196
+ const res = await postMcp(port);
197
+ expect(calls).toEqual(["reject"]);
198
+ expect(res.status).toBe(401);
199
+ expect(await res.json()).toEqual({ error: "Unauthorized" });
200
+ });
201
+ it("runs multiple global middleware in registration order", async () => {
202
+ const { createApp } = await import("./express.js");
203
+ const calls = [];
204
+ const mwA = (_req, _res, next) => {
205
+ calls.push("A");
206
+ next();
207
+ };
208
+ const mwB = (_req, _res, next) => {
209
+ calls.push("B");
210
+ next();
211
+ };
212
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
213
+ app.use(mwA);
214
+ app.use(mwB);
215
+ const httpServer = http.createServer();
216
+ const expressApp = await createApp({ app, httpServer });
217
+ const { port, server: httpListening } = await listen(expressApp);
218
+ openServer = httpListening;
219
+ await postMcp(port);
220
+ expect(calls).toEqual(["A", "B"]);
221
+ });
222
+ it("path-scoped middleware does not run on non-matching paths", async () => {
223
+ const { createApp } = await import("./express.js");
224
+ const calls = [];
225
+ const apiMw = (_req, _res, next) => {
226
+ calls.push("api");
227
+ next();
228
+ };
229
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
230
+ app.use("/api", apiMw);
231
+ const httpServer = http.createServer();
232
+ const expressApp = await createApp({ app, httpServer });
233
+ const { port, server: httpListening } = await listen(expressApp);
234
+ openServer = httpListening;
235
+ // Hit /mcp — the /api middleware should NOT fire
236
+ await postMcp(port);
237
+ expect(calls).toEqual([]);
238
+ });
239
+ it("supports Express Router via custom middleware", async () => {
240
+ const { createApp } = await import("./express.js");
241
+ const { Router } = await import("express");
242
+ const router = Router();
243
+ router.get("/health", (_req, res) => {
244
+ res.json({ status: "ok" });
245
+ });
246
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
247
+ app.use(router);
248
+ const httpServer = http.createServer();
249
+ const expressApp = await createApp({ app, httpServer });
250
+ const { port, server: httpListening } = await listen(expressApp);
251
+ openServer = httpListening;
252
+ const res = await fetch(`http://localhost:${port}/health`);
253
+ expect(res.status).toBe(200);
254
+ expect(await res.json()).toEqual({ status: "ok" });
255
+ });
256
+ it("supports path-prefixed Router", async () => {
257
+ const { createApp } = await import("./express.js");
258
+ const { Router } = await import("express");
259
+ const router = Router();
260
+ router.get("/data", (_req, res) => {
261
+ res.json({ value: 42 });
262
+ });
263
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
264
+ app.use("/api", router);
265
+ const httpServer = http.createServer();
266
+ const expressApp = await createApp({ app, httpServer });
267
+ const { port, server: httpListening } = await listen(expressApp);
268
+ openServer = httpListening;
269
+ const res = await fetch(`http://localhost:${port}/api/data`);
270
+ expect(res.status).toBe(200);
271
+ expect(await res.json()).toEqual({ value: 42 });
272
+ });
273
+ it("server survives middleware errors without crashing", async () => {
274
+ const { createApp } = await import("./express.js");
275
+ const throwing = () => {
276
+ throw new Error("boom");
277
+ };
278
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
279
+ app.use("/explode", throwing);
280
+ const httpServer = http.createServer();
281
+ const expressApp = await createApp({ app, httpServer });
282
+ const { port, server: httpListening } = await listen(expressApp);
283
+ openServer = httpListening;
284
+ const res = await fetch(`http://localhost:${port}/explode`);
285
+ expect(res.status).toBe(500);
286
+ // Server process did not crash — it still accepts connections
287
+ const followUp = await fetch(`http://localhost:${port}/explode`);
288
+ expect(followUp.status).toBe(500);
289
+ });
290
+ it("returns 500 JSON-RPC error when the MCP handler throws and no error middleware is registered", async () => {
291
+ const { createApp } = await import("./express.js");
292
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
293
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
294
+ // Force the express-level error path: make a /mcp middleware throw so the
295
+ // error pipeline runs and lands in the default /mcp error handler.
296
+ app.use("/mcp", () => {
297
+ throw new Error("boom");
298
+ });
299
+ const httpServer = http.createServer();
300
+ const expressApp = await createApp({ app, httpServer });
301
+ const { port, server: httpListening } = await listen(expressApp);
302
+ openServer = httpListening;
303
+ const res = await postMcp(port);
304
+ expect(res.status).toBe(500);
305
+ expect(await res.json()).toEqual({
306
+ jsonrpc: "2.0",
307
+ error: { code: -32603, message: "Internal server error" },
308
+ id: null,
309
+ });
310
+ expect(consoleSpy).toHaveBeenCalledWith("Error handling MCP request:", expect.any(Error));
311
+ consoleSpy.mockRestore();
312
+ });
313
+ it("invokes a custom error handler when the MCP handler throws", async () => {
314
+ const { createApp } = await import("./express.js");
315
+ const calls = [];
316
+ const errorHandler = (_err, _req, res, _next) => {
317
+ calls.push("error-handler");
318
+ res.status(503).json({ custom: true });
319
+ };
320
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
321
+ app.use("/mcp", () => {
322
+ throw new Error("boom");
323
+ });
324
+ const httpServer = http.createServer();
325
+ const expressApp = await createApp({
326
+ app,
327
+ httpServer,
328
+ errorMiddleware: [{ handlers: [errorHandler] }],
329
+ });
330
+ const { port, server: httpListening } = await listen(expressApp);
331
+ openServer = httpListening;
332
+ const res = await postMcp(port);
333
+ expect(calls).toEqual(["error-handler"]);
334
+ expect(res.status).toBe(503);
335
+ expect(await res.json()).toEqual({ custom: true });
336
+ });
337
+ it("invokes a path-scoped error handler only for matching routes", async () => {
338
+ const { createApp } = await import("./express.js");
339
+ const calls = [];
340
+ const mcpErrorHandler = (_err, _req, res, _next) => {
341
+ calls.push("mcp-error-handler");
342
+ res.status(503).json({ from: "mcp-error-handler" });
343
+ };
344
+ const throwingApiRoute = (_req, _res, next) => {
345
+ next(new Error("api error"));
346
+ };
347
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
348
+ app.use("/mcp", () => {
349
+ throw new Error("boom");
350
+ });
351
+ app.use("/api/test", throwingApiRoute);
352
+ const httpServer = http.createServer();
353
+ const expressApp = await createApp({
354
+ app,
355
+ httpServer,
356
+ errorMiddleware: [{ path: "/mcp", handlers: [mcpErrorHandler] }],
357
+ });
358
+ const { port, server: httpListening } = await listen(expressApp);
359
+ openServer = httpListening;
360
+ const mcpRes = await postMcp(port);
361
+ expect(calls).toEqual(["mcp-error-handler"]);
362
+ expect(mcpRes.status).toBe(503);
363
+ expect(await mcpRes.json()).toEqual({ from: "mcp-error-handler" });
364
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
365
+ const apiRes = await postApi(port);
366
+ expect(calls).toEqual(["mcp-error-handler"]);
367
+ expect(apiRes.status).toBe(500);
368
+ consoleSpy.mockRestore();
369
+ });
370
+ it("handles concurrent /mcp requests without 'Already connected to a transport'", async () => {
371
+ const { createApp } = await import("./express.js");
372
+ // Slow tool: keeps the underlying transport bound long enough to overlap
373
+ // with concurrent requests, exposing the shared-McpServer race.
374
+ const app = new Skybridge({ name: "concurrent-test", version: "0.0.0" }, (server) => server.registerTool({ name: "slow", description: "slow" }, async () => {
375
+ await new Promise((r) => setTimeout(r, 50));
376
+ return { content: [{ type: "text", text: "done" }] };
377
+ }));
378
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
379
+ const httpServer = http.createServer();
380
+ const expressApp = await createApp({ app, httpServer });
381
+ const { port, server } = await listen(expressApp);
382
+ openServer = server;
383
+ const callBody = (id) => JSON.stringify({
384
+ jsonrpc: "2.0",
385
+ method: "tools/call",
386
+ id,
387
+ params: { name: "slow", arguments: {} },
388
+ });
389
+ const N = 10;
390
+ const responses = await Promise.all(Array.from({ length: N }, (_, i) => fetch(`http://localhost:${port}/mcp`, {
391
+ method: "POST",
392
+ headers: {
393
+ "Content-Type": "application/json",
394
+ Accept: "application/json, text/event-stream",
395
+ },
396
+ body: callBody(i + 1),
397
+ })));
398
+ expect(responses.map((r) => r.status)).toEqual(Array(N).fill(200));
399
+ expect(consoleSpy).not.toHaveBeenCalledWith("Error handling MCP request:", expect.any(Error));
400
+ consoleSpy.mockRestore();
401
+ });
402
+ });
403
+ describe("createApp Vercel mode", () => {
404
+ it("app.run() returns the Express app without binding a port when VERCEL=1", async () => {
405
+ const prevVercel = process.env.VERCEL;
406
+ const prevEnv = process.env.NODE_ENV;
407
+ process.env.VERCEL = "1";
408
+ process.env.NODE_ENV = "production";
409
+ try {
410
+ vi.resetModules();
411
+ const { Skybridge: Reloaded } = await import("./app.js");
412
+ const app = new Reloaded({ name: "t", version: "0.0.0" }, (server) => server);
413
+ const result = await app.run();
414
+ expect(typeof result).toBe("function");
415
+ expect(result).toBe(app.express);
416
+ const { port, server: listening } = await listen(app.express);
417
+ openServer = listening;
418
+ const res = await postMcp(port);
419
+ expect(res.status).not.toBe(404);
420
+ }
421
+ finally {
422
+ if (prevVercel === undefined) {
423
+ delete process.env.VERCEL;
424
+ }
425
+ else {
426
+ process.env.VERCEL = prevVercel;
427
+ }
428
+ process.env.NODE_ENV = prevEnv;
429
+ vi.resetModules();
430
+ }
431
+ });
432
+ });
433
+ describe("createApp tunnel routes", () => {
434
+ it("proxies POST /__skybridge/tunnel to the cli control server in dev mode", async () => {
435
+ // Stand up a fake control listener that returns a known JSON body.
436
+ const control = http.createServer((_req, res) => {
437
+ res.writeHead(200, { "Content-Type": "application/json" });
438
+ res.end('{"status":"idle"}');
439
+ });
440
+ await new Promise((resolve) => control.listen(0, "127.0.0.1", resolve));
441
+ const controlAddr = control.address();
442
+ if (typeof controlAddr === "string" || controlAddr === null) {
443
+ control.close();
444
+ throw new Error("control server has no address");
445
+ }
446
+ const controlPort = controlAddr.port;
447
+ const prev = process.env.__TUNNEL_CONTROL_PORT;
448
+ process.env.__TUNNEL_CONTROL_PORT = String(controlPort);
449
+ try {
450
+ const { createApp } = await import("./express.js");
451
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server);
452
+ const httpServer = http.createServer();
453
+ const expressApp = await createApp({ app, httpServer });
454
+ const { port, server } = await listen(expressApp);
455
+ openServer = server;
456
+ const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {
457
+ method: "POST",
458
+ });
459
+ expect(res.status).toBe(200);
460
+ expect(await res.json()).toEqual({ status: "idle" });
461
+ }
462
+ finally {
463
+ if (prev === undefined) {
464
+ delete process.env.__TUNNEL_CONTROL_PORT;
465
+ }
466
+ else {
467
+ process.env.__TUNNEL_CONTROL_PORT = prev;
468
+ }
469
+ await new Promise((resolve) => control.close(() => resolve()));
470
+ }
471
+ });
472
+ it("does not expose /__skybridge/tunnel in production mode", async () => {
473
+ const prevEnv = process.env.NODE_ENV;
474
+ process.env.NODE_ENV = "production";
475
+ try {
476
+ vi.resetModules();
477
+ const { createApp } = await import("./express.js");
478
+ const { Skybridge: ReloadedSkybridge } = await import("./app.js");
479
+ const app = new ReloadedSkybridge({ name: "t", version: "0.0.0" }, (server) => server);
480
+ const httpServer = http.createServer();
481
+ const expressApp = await createApp({ app, httpServer });
482
+ const { port, server } = await listen(expressApp);
483
+ openServer = server;
484
+ const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {
485
+ method: "POST",
486
+ });
487
+ expect(res.status).toBe(404);
488
+ }
489
+ finally {
490
+ process.env.NODE_ENV = prevEnv;
491
+ vi.resetModules();
492
+ }
493
+ });
494
+ });
495
+ describe("createApp mount path", () => {
496
+ it("serves /mcp with the mount path intact on the request URL", async () => {
497
+ const { createApp } = await import("./express.js");
498
+ const app = new Skybridge({ name: "t", version: "0.0.0" }, (server) => server.registerTool({
499
+ name: "echo-url",
500
+ description: "Echoes the request URL.",
501
+ inputSchema: {},
502
+ }, (_args, extra) => ({
503
+ content: [{ type: "text", text: extra.http?.req?.url ?? "" }],
504
+ })));
505
+ const httpServer = http.createServer();
506
+ const expressApp = await createApp({ app, httpServer });
507
+ const { port, server } = await listen(expressApp);
508
+ openServer = server;
509
+ const client = new Client({ name: "test-client", version: "0.0.0" });
510
+ await client.connect(new StreamableHTTPClientTransport(new URL(`http://localhost:${port}/mcp`)));
511
+ const result = (await client.callTool({
512
+ name: "echo-url",
513
+ arguments: {},
514
+ }));
515
+ await client.close();
516
+ expect(new URL(result.content[0]?.text ?? "").pathname).toBe("/mcp");
517
+ });
518
+ });
519
+ //# sourceMappingURL=express.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.test.js","sourceRoot":"","sources":["../../src/server/express.test.ts"],"names":[],"mappings":"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","sourcesContent":["import http from \"node:http\";\nimport {\n Client,\n StreamableHTTPClientTransport,\n} from \"@modelcontextprotocol/client\";\nimport type { ErrorRequestHandler, RequestHandler } from \"express\";\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { Skybridge } from \"./app.js\";\n\nvi.mock(\"@skybridge/devtools\", () => ({\n devtoolsStaticServer: () =>\n ((_req: unknown, _res: unknown, next: () => void) =>\n next()) as RequestHandler,\n}));\n\nvi.mock(\"./viewsDevServer.js\", () => ({\n viewsDevServer: (_httpServer: unknown) =>\n ((_req: unknown, _res: unknown, next: () => void) =>\n next()) as RequestHandler,\n}));\n\nasync function listen(app: Parameters<typeof http.createServer>[1]) {\n const server = http.createServer(app);\n await new Promise<void>((resolve) => server.listen(0, resolve));\n const port = (server.address() as { port: number }).port;\n return { port, server };\n}\n\nlet openServer: http.Server | undefined;\nafterEach(() => openServer?.close());\n\nasync function postMcp(port: number) {\n return fetch(`http://localhost:${port}/mcp`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ jsonrpc: \"2.0\", method: \"initialize\", id: 1 }),\n });\n}\n\nasync function postApi(port: number) {\n return fetch(`http://localhost:${port}/api/test`, { method: \"POST\" });\n}\n\ndescribe(\"Skybridge.express\", () => {\n it(\"exposes a ready Express app immediately after construction\", () => {\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n expect(app.express).toBeDefined();\n expect(typeof app.express.use).toBe(\"function\");\n expect(typeof app.express.get).toBe(\"function\");\n });\n\n it(\"app.express.get registers a route reachable alongside /mcp\", async () => {\n const { createApp } = await import(\"./express.js\");\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.express.get(\"/health\", (_req, res) => {\n res.json({ status: \"ok\" });\n });\n\n const httpServer = http.createServer();\n await createApp({ app, httpServer });\n const { port, server: listening } = await listen(app.express);\n openServer = listening;\n\n const health = await fetch(`http://localhost:${port}/health`);\n expect(health.status).toBe(200);\n expect(await health.json()).toEqual({ status: \"ok\" });\n\n // /mcp still works (POST returns 200/4xx, not 404)\n const mcp = await postMcp(port);\n expect(mcp.status).not.toBe(404);\n });\n\n it(\"app.use and app.express.use produce the same registration order\", async () => {\n const { createApp } = await import(\"./express.js\");\n const callsA: string[] = [];\n const callsB: string[] = [];\n\n const buildApp = () =>\n new Skybridge({ name: \"t\", version: \"0.0.0\" }, (server) => server);\n\n const sA = buildApp();\n sA.use((_req, _res, next) => {\n callsA.push(\"first\");\n next();\n });\n sA.express.use((_req, _res, next) => {\n callsA.push(\"second\");\n next();\n });\n\n const sB = buildApp();\n sB.express.use((_req, _res, next) => {\n callsB.push(\"first\");\n next();\n });\n sB.use((_req, _res, next) => {\n callsB.push(\"second\");\n next();\n });\n\n for (const s of [sA, sB]) {\n s.express.get(\"/probe\", (_req, res) => res.json({ ok: true }));\n const httpServer = http.createServer();\n await createApp({ app: s, httpServer });\n const { port, server: listening } = await listen(s.express);\n openServer = listening;\n await fetch(`http://localhost:${port}/probe`);\n listening.close();\n }\n\n expect(callsA).toEqual([\"first\", \"second\"]);\n expect(callsB).toEqual([\"first\", \"second\"]);\n });\n\n it(\"useOnError still wraps thrown /mcp errors after the route is mounted\", async () => {\n const { createApp } = await import(\"./express.js\");\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n // Register the error handler BEFORE createApp — useOnError should still\n // apply it after /mcp, so /mcp errors hit it.\n const seen: string[] = [];\n app.useOnError((_err, _req, res, _next) => {\n seen.push(\"useOnError\");\n res.status(503).json({ from: \"useOnError\" });\n });\n\n // Force the /mcp handler to throw so the error pipeline runs.\n app.use(\"/mcp\", () => {\n throw new Error(\"boom\");\n });\n\n const httpServer = http.createServer();\n await createApp({\n app,\n httpServer,\n // Mirror what run() does: forward the app's useOnError handlers\n // to createApp so they get applied after /mcp.\n // biome-ignore lint/complexity/useLiteralKeys: test mirrors run() internals to verify useOnError ordering\n errorMiddleware: app[\"errorMiddleware\"],\n });\n const { port, server: listening } = await listen(app.express);\n openServer = listening;\n\n const res = await postMcp(port);\n expect(seen).toEqual([\"useOnError\"]);\n expect(res.status).toBe(503);\n expect(await res.json()).toEqual({ from: \"useOnError\" });\n });\n});\n\ndescribe(\"Skybridge JSON body parser options\", () => {\n const largeBody = JSON.stringify({ data: \"x\".repeat(200 * 1024) });\n\n async function postEcho(port: number, body: string) {\n return fetch(`http://localhost:${port}/echo`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body,\n });\n }\n\n it(\"forwards json options to express.json\", async () => {\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\", json: { limit: \"10mb\" } },\n (server) => server,\n );\n app.express.post(\"/echo\", (req, res) => {\n res.json({ received: req.body.data.length });\n });\n const { port, server: listening } = await listen(app.express);\n openServer = listening;\n\n const res = await postEcho(port, largeBody);\n expect(res.status).toBe(200);\n expect(await res.json()).toEqual({ received: 200 * 1024 });\n });\n\n it(\"keeps the default 100kb limit when no options are passed\", async () => {\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.express.post(\"/echo\", (_req, res) => {\n res.json({ ok: true });\n });\n const { port, server: listening } = await listen(app.express);\n openServer = listening;\n\n const res = await postEcho(port, largeBody);\n expect(res.status).toBe(413);\n });\n});\n\ndescribe(\"createApp\", () => {\n it(\"runs global custom middleware before the /mcp handler\", async () => {\n const { createApp } = await import(\"./express.js\");\n const calls: string[] = [];\n\n const mw: RequestHandler = (_req, _res, next) => {\n calls.push(\"custom\");\n next();\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(mw);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n await postMcp(port);\n expect(calls).toEqual([\"custom\"]);\n });\n\n it(\"runs path-scoped middleware on /mcp\", async () => {\n const { createApp } = await import(\"./express.js\");\n const calls: string[] = [];\n\n const mw: RequestHandler = (_req, _res, next) => {\n calls.push(\"auth\");\n next();\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(\"/mcp\", mw);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n await postMcp(port);\n expect(calls).toEqual([\"auth\"]);\n });\n\n it(\"allows middleware to short-circuit with 401\", async () => {\n const { createApp } = await import(\"./express.js\");\n const calls: string[] = [];\n\n const reject: RequestHandler = (_req, res) => {\n calls.push(\"reject\");\n res.status(401).json({ error: \"Unauthorized\" });\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(\"/mcp\", reject);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n const res = await postMcp(port);\n expect(calls).toEqual([\"reject\"]);\n expect(res.status).toBe(401);\n expect(await res.json()).toEqual({ error: \"Unauthorized\" });\n });\n\n it(\"runs multiple global middleware in registration order\", async () => {\n const { createApp } = await import(\"./express.js\");\n const calls: string[] = [];\n\n const mwA: RequestHandler = (_req, _res, next) => {\n calls.push(\"A\");\n next();\n };\n const mwB: RequestHandler = (_req, _res, next) => {\n calls.push(\"B\");\n next();\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(mwA);\n app.use(mwB);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n await postMcp(port);\n expect(calls).toEqual([\"A\", \"B\"]);\n });\n\n it(\"path-scoped middleware does not run on non-matching paths\", async () => {\n const { createApp } = await import(\"./express.js\");\n const calls: string[] = [];\n\n const apiMw: RequestHandler = (_req, _res, next) => {\n calls.push(\"api\");\n next();\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(\"/api\", apiMw);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n // Hit /mcp — the /api middleware should NOT fire\n await postMcp(port);\n expect(calls).toEqual([]);\n });\n\n it(\"supports Express Router via custom middleware\", async () => {\n const { createApp } = await import(\"./express.js\");\n const { Router } = await import(\"express\");\n\n const router = Router();\n router.get(\"/health\", (_req, res) => {\n res.json({ status: \"ok\" });\n });\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(router as RequestHandler);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n const res = await fetch(`http://localhost:${port}/health`);\n expect(res.status).toBe(200);\n expect(await res.json()).toEqual({ status: \"ok\" });\n });\n\n it(\"supports path-prefixed Router\", async () => {\n const { createApp } = await import(\"./express.js\");\n const { Router } = await import(\"express\");\n\n const router = Router();\n router.get(\"/data\", (_req, res) => {\n res.json({ value: 42 });\n });\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(\"/api\", router as RequestHandler);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n const res = await fetch(`http://localhost:${port}/api/data`);\n expect(res.status).toBe(200);\n expect(await res.json()).toEqual({ value: 42 });\n });\n\n it(\"server survives middleware errors without crashing\", async () => {\n const { createApp } = await import(\"./express.js\");\n\n const throwing: RequestHandler = () => {\n throw new Error(\"boom\");\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(\"/explode\", throwing);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n const res = await fetch(`http://localhost:${port}/explode`);\n expect(res.status).toBe(500);\n\n // Server process did not crash — it still accepts connections\n const followUp = await fetch(`http://localhost:${port}/explode`);\n expect(followUp.status).toBe(500);\n });\n\n it(\"returns 500 JSON-RPC error when the MCP handler throws and no error middleware is registered\", async () => {\n const { createApp } = await import(\"./express.js\");\n const consoleSpy = vi.spyOn(console, \"error\").mockImplementation(() => {});\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n // Force the express-level error path: make a /mcp middleware throw so the\n // error pipeline runs and lands in the default /mcp error handler.\n app.use(\"/mcp\", () => {\n throw new Error(\"boom\");\n });\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n const res = await postMcp(port);\n expect(res.status).toBe(500);\n expect(await res.json()).toEqual({\n jsonrpc: \"2.0\",\n error: { code: -32603, message: \"Internal server error\" },\n id: null,\n });\n expect(consoleSpy).toHaveBeenCalledWith(\n \"Error handling MCP request:\",\n expect.any(Error),\n );\n consoleSpy.mockRestore();\n });\n\n it(\"invokes a custom error handler when the MCP handler throws\", async () => {\n const { createApp } = await import(\"./express.js\");\n const calls: string[] = [];\n\n const errorHandler: ErrorRequestHandler = (_err, _req, res, _next) => {\n calls.push(\"error-handler\");\n res.status(503).json({ custom: true });\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(\"/mcp\", () => {\n throw new Error(\"boom\");\n });\n\n const httpServer = http.createServer();\n const expressApp = await createApp({\n app,\n httpServer,\n errorMiddleware: [{ handlers: [errorHandler] }],\n });\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n const res = await postMcp(port);\n expect(calls).toEqual([\"error-handler\"]);\n expect(res.status).toBe(503);\n expect(await res.json()).toEqual({ custom: true });\n });\n\n it(\"invokes a path-scoped error handler only for matching routes\", async () => {\n const { createApp } = await import(\"./express.js\");\n const calls: string[] = [];\n\n const mcpErrorHandler: ErrorRequestHandler = (_err, _req, res, _next) => {\n calls.push(\"mcp-error-handler\");\n res.status(503).json({ from: \"mcp-error-handler\" });\n };\n\n const throwingApiRoute: RequestHandler = (_req, _res, next) => {\n next(new Error(\"api error\"));\n };\n\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n app.use(\"/mcp\", () => {\n throw new Error(\"boom\");\n });\n app.use(\"/api/test\", throwingApiRoute);\n\n const httpServer = http.createServer();\n const expressApp = await createApp({\n app,\n httpServer,\n errorMiddleware: [{ path: \"/mcp\", handlers: [mcpErrorHandler] }],\n });\n const { port, server: httpListening } = await listen(expressApp);\n openServer = httpListening;\n\n const mcpRes = await postMcp(port);\n expect(calls).toEqual([\"mcp-error-handler\"]);\n expect(mcpRes.status).toBe(503);\n expect(await mcpRes.json()).toEqual({ from: \"mcp-error-handler\" });\n\n const consoleSpy = vi.spyOn(console, \"error\").mockImplementation(() => {});\n const apiRes = await postApi(port);\n expect(calls).toEqual([\"mcp-error-handler\"]);\n expect(apiRes.status).toBe(500);\n consoleSpy.mockRestore();\n });\n\n it(\"handles concurrent /mcp requests without 'Already connected to a transport'\", async () => {\n const { createApp } = await import(\"./express.js\");\n\n // Slow tool: keeps the underlying transport bound long enough to overlap\n // with concurrent requests, exposing the shared-McpServer race.\n const app = new Skybridge(\n { name: \"concurrent-test\", version: \"0.0.0\" },\n (server) =>\n server.registerTool({ name: \"slow\", description: \"slow\" }, async () => {\n await new Promise((r) => setTimeout(r, 50));\n return { content: [{ type: \"text\" as const, text: \"done\" }] };\n }),\n );\n\n const consoleSpy = vi.spyOn(console, \"error\").mockImplementation(() => {});\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n const { port, server } = await listen(expressApp);\n openServer = server;\n\n const callBody = (id: number) =>\n JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n id,\n params: { name: \"slow\", arguments: {} },\n });\n\n const N = 10;\n const responses = await Promise.all(\n Array.from({ length: N }, (_, i) =>\n fetch(`http://localhost:${port}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n },\n body: callBody(i + 1),\n }),\n ),\n );\n\n expect(responses.map((r) => r.status)).toEqual(Array(N).fill(200));\n expect(consoleSpy).not.toHaveBeenCalledWith(\n \"Error handling MCP request:\",\n expect.any(Error),\n );\n consoleSpy.mockRestore();\n });\n});\n\ndescribe(\"createApp Vercel mode\", () => {\n it(\"app.run() returns the Express app without binding a port when VERCEL=1\", async () => {\n const prevVercel = process.env.VERCEL;\n const prevEnv = process.env.NODE_ENV;\n process.env.VERCEL = \"1\";\n process.env.NODE_ENV = \"production\";\n try {\n vi.resetModules();\n const { Skybridge: Reloaded } = await import(\"./app.js\");\n const app = new Reloaded(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n const result = await app.run();\n expect(typeof result).toBe(\"function\");\n expect(result).toBe(app.express);\n const { port, server: listening } = await listen(app.express);\n openServer = listening;\n const res = await postMcp(port);\n expect(res.status).not.toBe(404);\n } finally {\n if (prevVercel === undefined) {\n delete process.env.VERCEL;\n } else {\n process.env.VERCEL = prevVercel;\n }\n process.env.NODE_ENV = prevEnv;\n vi.resetModules();\n }\n });\n});\n\ndescribe(\"createApp tunnel routes\", () => {\n it(\"proxies POST /__skybridge/tunnel to the cli control server in dev mode\", async () => {\n // Stand up a fake control listener that returns a known JSON body.\n const control = http.createServer((_req, res) => {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end('{\"status\":\"idle\"}');\n });\n await new Promise<void>((resolve) =>\n control.listen(0, \"127.0.0.1\", resolve),\n );\n const controlAddr = control.address();\n if (typeof controlAddr === \"string\" || controlAddr === null) {\n control.close();\n throw new Error(\"control server has no address\");\n }\n const controlPort = controlAddr.port;\n\n const prev = process.env.__TUNNEL_CONTROL_PORT;\n process.env.__TUNNEL_CONTROL_PORT = String(controlPort);\n try {\n const { createApp } = await import(\"./express.js\");\n const app = new Skybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n const { port, server } = await listen(expressApp);\n openServer = server;\n\n const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n expect(res.status).toBe(200);\n expect(await res.json()).toEqual({ status: \"idle\" });\n } finally {\n if (prev === undefined) {\n delete process.env.__TUNNEL_CONTROL_PORT;\n } else {\n process.env.__TUNNEL_CONTROL_PORT = prev;\n }\n await new Promise<void>((resolve) => control.close(() => resolve()));\n }\n });\n\n it(\"does not expose /__skybridge/tunnel in production mode\", async () => {\n const prevEnv = process.env.NODE_ENV;\n process.env.NODE_ENV = \"production\";\n try {\n vi.resetModules();\n const { createApp } = await import(\"./express.js\");\n const { Skybridge: ReloadedSkybridge } = await import(\"./app.js\");\n const app = new ReloadedSkybridge(\n { name: \"t\", version: \"0.0.0\" },\n (server) => server,\n );\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n const { port, server } = await listen(expressApp);\n openServer = server;\n\n const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n expect(res.status).toBe(404);\n } finally {\n process.env.NODE_ENV = prevEnv;\n vi.resetModules();\n }\n });\n});\n\ndescribe(\"createApp mount path\", () => {\n it(\"serves /mcp with the mount path intact on the request URL\", async () => {\n const { createApp } = await import(\"./express.js\");\n const app = new Skybridge({ name: \"t\", version: \"0.0.0\" }, (server) =>\n server.registerTool(\n {\n name: \"echo-url\",\n description: \"Echoes the request URL.\",\n inputSchema: {},\n },\n (_args, extra) => ({\n content: [{ type: \"text\", text: extra.http?.req?.url ?? \"\" }],\n }),\n ),\n );\n\n const httpServer = http.createServer();\n const expressApp = await createApp({ app, httpServer });\n const { port, server } = await listen(expressApp);\n openServer = server;\n\n const client = new Client({ name: \"test-client\", version: \"0.0.0\" });\n await client.connect(\n new StreamableHTTPClientTransport(\n new URL(`http://localhost:${port}/mcp`),\n ),\n );\n const result = (await client.callTool({\n name: \"echo-url\",\n arguments: {},\n })) as unknown as { content: { text: string }[] };\n await client.close();\n\n expect(new URL(result.content[0]?.text ?? \"\").pathname).toBe(\"/mcp\");\n });\n});\n"]}