skybridge 0.0.0-dev.c003b05 → 0.0.0-dev.c006b0b

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 (483) hide show
  1. package/README.md +126 -124
  2. package/dist/cli/build-helpers.d.ts +11 -0
  3. package/dist/cli/build-helpers.js +107 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +132 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -0
  7. package/dist/cli/build-steps.d.ts +2 -0
  8. package/dist/cli/build-steps.js +73 -0
  9. package/dist/cli/build-steps.js.map +1 -0
  10. package/dist/cli/build-steps.test.js +52 -0
  11. package/dist/cli/build-steps.test.js.map +1 -0
  12. package/dist/cli/detect-port.d.ts +2 -2
  13. package/dist/cli/detect-port.js +8 -20
  14. package/dist/cli/detect-port.js.map +1 -1
  15. package/dist/cli/header.d.ts +1 -1
  16. package/dist/cli/header.js.map +1 -1
  17. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  18. package/dist/cli/resolve-skybridge-config.js +18 -0
  19. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  20. package/dist/cli/run-command.js.map +1 -1
  21. package/dist/cli/run-plain.d.ts +18 -0
  22. package/dist/cli/run-plain.js +89 -0
  23. package/dist/cli/run-plain.js.map +1 -0
  24. package/dist/cli/telemetry.js.map +1 -1
  25. package/dist/cli/tunnel-control-server.d.ts +9 -0
  26. package/dist/cli/tunnel-control-server.js +31 -0
  27. package/dist/cli/tunnel-control-server.js.map +1 -0
  28. package/dist/cli/tunnel-control-server.test.js +39 -0
  29. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  30. package/dist/cli/tunnel-handler.d.ts +3 -0
  31. package/dist/cli/tunnel-handler.js +48 -0
  32. package/dist/cli/tunnel-handler.js.map +1 -0
  33. package/dist/cli/tunnel-handler.test.js +105 -0
  34. package/dist/cli/tunnel-handler.test.js.map +1 -0
  35. package/dist/cli/tunnel.d.ts +57 -0
  36. package/dist/cli/tunnel.js +154 -0
  37. package/dist/cli/tunnel.js.map +1 -0
  38. package/dist/cli/tunnel.test.js +190 -0
  39. package/dist/cli/tunnel.test.js.map +1 -0
  40. package/dist/cli/types.js.map +1 -1
  41. package/dist/cli/use-execute-steps.d.ts +1 -1
  42. package/dist/cli/use-execute-steps.js.map +1 -1
  43. package/dist/cli/use-messages.js.map +1 -1
  44. package/dist/cli/use-nodemon.d.ts +14 -0
  45. package/dist/cli/use-nodemon.js +82 -54
  46. package/dist/cli/use-nodemon.js.map +1 -1
  47. package/dist/cli/use-open-browser.d.ts +1 -0
  48. package/dist/cli/use-open-browser.js +44 -0
  49. package/dist/cli/use-open-browser.js.map +1 -0
  50. package/dist/cli/use-tunnel.d.ts +1 -1
  51. package/dist/cli/use-tunnel.js +102 -68
  52. package/dist/cli/use-tunnel.js.map +1 -1
  53. package/dist/cli/use-typescript-check.d.ts +9 -2
  54. package/dist/cli/use-typescript-check.js +89 -51
  55. package/dist/cli/use-typescript-check.js.map +1 -1
  56. package/dist/commands/build.d.ts +0 -3
  57. package/dist/commands/build.js +2 -38
  58. package/dist/commands/build.js.map +1 -1
  59. package/dist/commands/create.d.ts +9 -0
  60. package/dist/commands/create.js +30 -0
  61. package/dist/commands/create.js.map +1 -0
  62. package/dist/commands/dev.d.ts +2 -0
  63. package/dist/commands/dev.js +81 -2
  64. package/dist/commands/dev.js.map +1 -1
  65. package/dist/commands/start.js +7 -1
  66. package/dist/commands/start.js.map +1 -1
  67. package/dist/commands/telemetry/disable.js.map +1 -1
  68. package/dist/commands/telemetry/enable.js.map +1 -1
  69. package/dist/commands/telemetry/status.js.map +1 -1
  70. package/dist/context-warnings.d.ts +5 -0
  71. package/dist/context-warnings.js +31 -0
  72. package/dist/context-warnings.js.map +1 -0
  73. package/dist/context-warnings.test.js +28 -0
  74. package/dist/context-warnings.test.js.map +1 -0
  75. package/dist/server/app.d.ts +175 -0
  76. package/dist/server/app.js +275 -0
  77. package/dist/server/app.js.map +1 -0
  78. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  79. package/dist/server/asset-base-url-transform-plugin.js +17 -2
  80. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  81. package/dist/server/asset-base-url-transform-plugin.test.js +80 -1
  82. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  83. package/dist/server/auth/discovery.d.ts +33 -0
  84. package/dist/server/auth/discovery.js +56 -0
  85. package/dist/server/auth/discovery.js.map +1 -0
  86. package/dist/server/auth/discovery.test.d.ts +1 -0
  87. package/dist/server/auth/discovery.test.js +93 -0
  88. package/dist/server/auth/discovery.test.js.map +1 -0
  89. package/dist/server/auth/index.d.ts +30 -0
  90. package/dist/server/auth/index.js +2 -0
  91. package/dist/server/auth/index.js.map +1 -0
  92. package/dist/server/auth/providers/auth0.d.ts +40 -0
  93. package/dist/server/auth/providers/auth0.js +31 -0
  94. package/dist/server/auth/providers/auth0.js.map +1 -0
  95. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  96. package/dist/server/auth/providers/auth0.test.js +50 -0
  97. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  98. package/dist/server/auth/providers/authplane.d.ts +49 -0
  99. package/dist/server/auth/providers/authplane.js +57 -0
  100. package/dist/server/auth/providers/authplane.js.map +1 -0
  101. package/dist/server/auth/providers/authplane.test.d.ts +1 -0
  102. package/dist/server/auth/providers/authplane.test.js +140 -0
  103. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  104. package/dist/server/auth/providers/clerk.d.ts +51 -0
  105. package/dist/server/auth/providers/clerk.js +19 -0
  106. package/dist/server/auth/providers/clerk.js.map +1 -0
  107. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  108. package/dist/server/auth/providers/clerk.test.js +30 -0
  109. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  110. package/dist/server/auth/providers/custom.d.ts +40 -0
  111. package/dist/server/auth/providers/custom.js +56 -0
  112. package/dist/server/auth/providers/custom.js.map +1 -0
  113. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  114. package/dist/server/auth/providers/custom.test.js +158 -0
  115. package/dist/server/auth/providers/custom.test.js.map +1 -0
  116. package/dist/server/auth/providers/descope.d.ts +44 -0
  117. package/dist/server/auth/providers/descope.js +44 -0
  118. package/dist/server/auth/providers/descope.js.map +1 -0
  119. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  120. package/dist/server/auth/providers/descope.test.js +62 -0
  121. package/dist/server/auth/providers/descope.test.js.map +1 -0
  122. package/dist/server/auth/providers/shared.d.ts +2 -0
  123. package/dist/server/auth/providers/shared.js +6 -0
  124. package/dist/server/auth/providers/shared.js.map +1 -0
  125. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  126. package/dist/server/auth/providers/shared.test.js +10 -0
  127. package/dist/server/auth/providers/shared.test.js.map +1 -0
  128. package/dist/server/auth/providers/stytch.d.ts +25 -0
  129. package/dist/server/auth/providers/stytch.js +16 -0
  130. package/dist/server/auth/providers/stytch.js.map +1 -0
  131. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  132. package/dist/server/auth/providers/verify-spy.js +21 -0
  133. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  134. package/dist/server/auth/providers/workos.d.ts +33 -0
  135. package/dist/server/auth/providers/workos.js +15 -0
  136. package/dist/server/auth/providers/workos.js.map +1 -0
  137. package/dist/server/auth/security-schemes.d.ts +23 -0
  138. package/dist/server/auth/security-schemes.js +64 -0
  139. package/dist/server/auth/security-schemes.js.map +1 -0
  140. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  141. package/dist/server/auth/security-schemes.test.js +99 -0
  142. package/dist/server/auth/security-schemes.test.js.map +1 -0
  143. package/dist/server/auth/setup.d.ts +6 -0
  144. package/dist/server/auth/setup.js +91 -0
  145. package/dist/server/auth/setup.js.map +1 -0
  146. package/dist/server/auth/setup.test.d.ts +1 -0
  147. package/dist/server/auth/setup.test.js +512 -0
  148. package/dist/server/auth/setup.test.js.map +1 -0
  149. package/dist/server/auth/verify.d.ts +46 -0
  150. package/dist/server/auth/verify.js +62 -0
  151. package/dist/server/auth/verify.js.map +1 -0
  152. package/dist/server/auth/verify.test.d.ts +1 -0
  153. package/dist/server/auth/verify.test.js +149 -0
  154. package/dist/server/auth/verify.test.js.map +1 -0
  155. package/dist/server/auth-extra.test-d.d.ts +1 -0
  156. package/dist/server/auth-extra.test-d.js +71 -0
  157. package/dist/server/auth-extra.test-d.js.map +1 -0
  158. package/dist/server/auth.d.ts +57 -0
  159. package/dist/server/auth.js +27 -0
  160. package/dist/server/auth.js.map +1 -0
  161. package/dist/server/build-manifest.test.d.ts +1 -0
  162. package/dist/server/build-manifest.test.js +28 -0
  163. package/dist/server/build-manifest.test.js.map +1 -0
  164. package/dist/server/content-helpers.d.ts +41 -1
  165. package/dist/server/content-helpers.js +33 -0
  166. package/dist/server/content-helpers.js.map +1 -1
  167. package/dist/server/content-helpers.test.js.map +1 -1
  168. package/dist/server/express.d.ts +23 -7
  169. package/dist/server/express.js +59 -30
  170. package/dist/server/express.js.map +1 -1
  171. package/dist/server/express.test.js +338 -71
  172. package/dist/server/express.test.js.map +1 -1
  173. package/dist/server/factory-loader.test.d.ts +1 -0
  174. package/dist/server/factory-loader.test.js +81 -0
  175. package/dist/server/factory-loader.test.js.map +1 -0
  176. package/dist/server/file-ref.d.ts +28 -0
  177. package/dist/server/file-ref.js +27 -0
  178. package/dist/server/file-ref.js.map +1 -0
  179. package/dist/server/host.d.ts +2 -0
  180. package/dist/server/host.js +11 -0
  181. package/dist/server/host.js.map +1 -0
  182. package/dist/server/host.test.d.ts +1 -0
  183. package/dist/server/host.test.js +13 -0
  184. package/dist/server/host.test.js.map +1 -0
  185. package/dist/server/index.d.ts +17 -2
  186. package/dist/server/index.js +14 -1
  187. package/dist/server/index.js.map +1 -1
  188. package/dist/server/inferUtilityTypes.d.ts +6 -6
  189. package/dist/server/inferUtilityTypes.js.map +1 -1
  190. package/dist/server/mcp-errors.test.d.ts +1 -0
  191. package/dist/server/mcp-errors.test.js +37 -0
  192. package/dist/server/mcp-errors.test.js.map +1 -0
  193. package/dist/server/metric.js.map +1 -1
  194. package/dist/server/middleware.d.ts +51 -13
  195. package/dist/server/middleware.js +33 -0
  196. package/dist/server/middleware.js.map +1 -1
  197. package/dist/server/middleware.test-d.js +1 -1
  198. package/dist/server/middleware.test-d.js.map +1 -1
  199. package/dist/server/middleware.test.js +190 -131
  200. package/dist/server/middleware.test.js.map +1 -1
  201. package/dist/server/register-tool.test.d.ts +1 -0
  202. package/dist/server/register-tool.test.js +23 -0
  203. package/dist/server/register-tool.test.js.map +1 -0
  204. package/dist/server/requestOrigin.d.ts +7 -0
  205. package/dist/server/requestOrigin.js +25 -0
  206. package/dist/server/requestOrigin.js.map +1 -0
  207. package/dist/server/server.d.ts +329 -41
  208. package/dist/server/server.js +469 -251
  209. package/dist/server/server.js.map +1 -1
  210. package/dist/server/skills-integration.test.d.ts +1 -0
  211. package/dist/server/skills-integration.test.js +79 -0
  212. package/dist/server/skills-integration.test.js.map +1 -0
  213. package/dist/server/skills.d.ts +27 -0
  214. package/dist/server/skills.js +188 -0
  215. package/dist/server/skills.js.map +1 -0
  216. package/dist/server/skills.test.d.ts +1 -0
  217. package/dist/server/skills.test.js +243 -0
  218. package/dist/server/skills.test.js.map +1 -0
  219. package/dist/server/templateHelper.d.ts +0 -5
  220. package/dist/server/templateHelper.js +3 -22
  221. package/dist/server/templateHelper.js.map +1 -1
  222. package/dist/server/templates.generated.d.ts +4 -0
  223. package/dist/server/templates.generated.js +43 -0
  224. package/dist/server/templates.generated.js.map +1 -0
  225. package/dist/server/tool-extra.test.d.ts +1 -0
  226. package/dist/server/tool-extra.test.js +72 -0
  227. package/dist/server/tool-extra.test.js.map +1 -0
  228. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  229. package/dist/server/tunnel-proxy-router.js +110 -0
  230. package/dist/server/tunnel-proxy-router.js.map +1 -0
  231. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  232. package/dist/server/tunnel-proxy-router.test.js +229 -0
  233. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  234. package/dist/server/view-name.test-d.d.ts +1 -0
  235. package/dist/server/view-name.test-d.js +8 -0
  236. package/dist/server/view-name.test-d.js.map +1 -0
  237. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  238. package/dist/server/view-resource-resolution.test.js +172 -0
  239. package/dist/server/view-resource-resolution.test.js.map +1 -0
  240. package/dist/server/viewsDevServer.js +4 -1
  241. package/dist/server/viewsDevServer.js.map +1 -1
  242. package/dist/test/utils.d.ts +9 -11
  243. package/dist/test/utils.js +18 -13
  244. package/dist/test/utils.js.map +1 -1
  245. package/dist/test/view.test.js +195 -113
  246. package/dist/test/view.test.js.map +1 -1
  247. package/dist/version.js +1 -3
  248. package/dist/version.js.map +1 -1
  249. package/dist/views/index.d.ts +10 -0
  250. package/dist/views/index.js +3 -0
  251. package/dist/views/index.js.map +1 -0
  252. package/dist/{web/plugin → views}/scan-views.d.ts +8 -0
  253. package/dist/{web/plugin → views}/scan-views.js +26 -8
  254. package/dist/views/scan-views.js.map +1 -0
  255. package/dist/views/scan-views.test.d.ts +1 -0
  256. package/dist/{web/plugin → views}/scan-views.test.js +33 -1
  257. package/dist/views/scan-views.test.js.map +1 -0
  258. package/dist/views/validate-view.d.ts +1 -0
  259. package/dist/{web/plugin → views}/validate-view.js +2 -2
  260. package/dist/views/validate-view.js.map +1 -0
  261. package/dist/views/validate-view.test.d.ts +1 -0
  262. package/dist/views/validate-view.test.js.map +1 -0
  263. package/dist/web/bridges/adaptor.d.ts +51 -0
  264. package/dist/web/bridges/adaptor.js +327 -0
  265. package/dist/web/bridges/adaptor.js.map +1 -0
  266. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  267. package/dist/web/bridges/adaptor.test.js +225 -0
  268. package/dist/web/bridges/adaptor.test.js.map +1 -0
  269. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -1
  270. package/dist/web/bridges/apps-sdk/bridge.js +15 -3
  271. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  272. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  273. package/dist/web/bridges/apps-sdk/index.js +0 -1
  274. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  275. package/dist/web/bridges/apps-sdk/types.d.ts +8 -1
  276. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  277. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  278. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  279. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  280. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  281. package/dist/web/bridges/get-adaptor.js +9 -7
  282. package/dist/web/bridges/get-adaptor.js.map +1 -1
  283. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  284. package/dist/web/bridges/get-adaptor.test.js +32 -0
  285. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  286. package/dist/web/bridges/index.js.map +1 -1
  287. package/dist/web/bridges/mcp-app/bridge.d.ts +15 -2
  288. package/dist/web/bridges/mcp-app/bridge.js +73 -7
  289. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  290. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  291. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  292. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  293. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  294. package/dist/web/bridges/mcp-app/index.js +0 -1
  295. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  296. package/dist/web/bridges/mcp-app/types.d.ts +2 -0
  297. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  298. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +12 -0
  299. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  300. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  301. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  302. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  303. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  304. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  305. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  306. package/dist/web/bridges/types.d.ts +120 -10
  307. package/dist/web/bridges/types.js +14 -1
  308. package/dist/web/bridges/types.js.map +1 -1
  309. package/dist/web/bridges/types.test.d.ts +1 -0
  310. package/dist/web/bridges/types.test.js +19 -0
  311. package/dist/web/bridges/types.test.js.map +1 -0
  312. package/dist/web/bridges/use-host-context.d.ts +5 -0
  313. package/dist/web/bridges/use-host-context.js +5 -0
  314. package/dist/web/bridges/use-host-context.js.map +1 -1
  315. package/dist/web/components/modal-provider.d.ts +1 -1
  316. package/dist/web/components/modal-provider.js +4 -3
  317. package/dist/web/components/modal-provider.js.map +1 -1
  318. package/dist/web/create-store.d.ts +26 -0
  319. package/dist/web/create-store.js +35 -9
  320. package/dist/web/create-store.js.map +1 -1
  321. package/dist/web/create-store.test.js +24 -23
  322. package/dist/web/create-store.test.js.map +1 -1
  323. package/dist/web/data-llm.d.ts +35 -2
  324. package/dist/web/data-llm.js +31 -3
  325. package/dist/web/data-llm.js.map +1 -1
  326. package/dist/web/data-llm.test.js +42 -29
  327. package/dist/web/data-llm.test.js.map +1 -1
  328. package/dist/web/generate-helpers.d.ts +15 -12
  329. package/dist/web/generate-helpers.js +12 -9
  330. package/dist/web/generate-helpers.js.map +1 -1
  331. package/dist/web/generate-helpers.test-d.js +14 -12
  332. package/dist/web/generate-helpers.test-d.js.map +1 -1
  333. package/dist/web/generate-helpers.test.js +2 -2
  334. package/dist/web/generate-helpers.test.js.map +1 -1
  335. package/dist/web/helpers/state.d.ts +2 -2
  336. package/dist/web/helpers/state.js +11 -11
  337. package/dist/web/helpers/state.js.map +1 -1
  338. package/dist/web/helpers/state.test.js +9 -9
  339. package/dist/web/helpers/state.test.js.map +1 -1
  340. package/dist/web/hooks/index.d.ts +7 -2
  341. package/dist/web/hooks/index.js +7 -2
  342. package/dist/web/hooks/index.js.map +1 -1
  343. package/dist/web/hooks/test/utils.d.ts +7 -2
  344. package/dist/web/hooks/test/utils.js +14 -3
  345. package/dist/web/hooks/test/utils.js.map +1 -1
  346. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  347. package/dist/web/hooks/use-call-tool.js +28 -0
  348. package/dist/web/hooks/use-call-tool.js.map +1 -1
  349. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  350. package/dist/web/hooks/use-call-tool.test.js +64 -29
  351. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  352. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  353. package/dist/web/hooks/use-display-mode.js +20 -0
  354. package/dist/web/hooks/use-display-mode.js.map +1 -1
  355. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  356. package/dist/web/hooks/use-display-mode.test.js +57 -21
  357. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  358. package/dist/web/hooks/use-download.d.ts +3 -0
  359. package/dist/web/hooks/use-download.js +7 -0
  360. package/dist/web/hooks/use-download.js.map +1 -0
  361. package/dist/web/hooks/use-download.test.d.ts +1 -0
  362. package/dist/web/hooks/use-download.test.js +103 -0
  363. package/dist/web/hooks/use-download.test.js.map +1 -0
  364. package/dist/web/hooks/use-files.d.ts +32 -0
  365. package/dist/web/hooks/use-files.js +32 -0
  366. package/dist/web/hooks/use-files.js.map +1 -1
  367. package/dist/web/hooks/use-files.test.js +11 -3
  368. package/dist/web/hooks/use-files.test.js.map +1 -1
  369. package/dist/web/hooks/use-host.d.ts +22 -0
  370. package/dist/web/hooks/use-host.js +30 -0
  371. package/dist/web/hooks/use-host.js.map +1 -0
  372. package/dist/web/hooks/use-host.test.d.ts +1 -0
  373. package/dist/web/hooks/use-host.test.js +59 -0
  374. package/dist/web/hooks/use-host.test.js.map +1 -0
  375. package/dist/web/hooks/use-open-external.d.ts +17 -0
  376. package/dist/web/hooks/use-open-external.js +16 -0
  377. package/dist/web/hooks/use-open-external.js.map +1 -1
  378. package/dist/web/hooks/use-open-external.test.js +15 -5
  379. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  380. package/dist/web/hooks/use-register-view-tool.d.ts +37 -0
  381. package/dist/web/hooks/use-register-view-tool.js +50 -0
  382. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  383. package/dist/web/hooks/use-request-close.d.ts +16 -0
  384. package/dist/web/hooks/use-request-close.js +21 -0
  385. package/dist/web/hooks/use-request-close.js.map +1 -0
  386. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  387. package/dist/web/hooks/use-request-close.test.js +47 -0
  388. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  389. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  390. package/dist/web/hooks/use-request-modal.js +19 -4
  391. package/dist/web/hooks/use-request-modal.js.map +1 -1
  392. package/dist/web/hooks/use-request-modal.test.js +12 -2
  393. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  394. package/dist/web/hooks/use-request-size.d.ts +20 -0
  395. package/dist/web/hooks/use-request-size.js +24 -0
  396. package/dist/web/hooks/use-request-size.js.map +1 -0
  397. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  398. package/dist/web/hooks/use-request-size.test.js +47 -0
  399. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  400. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  401. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  402. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  403. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  404. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  405. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  406. package/dist/web/hooks/use-set-open-in-app-url.test.js +26 -12
  407. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  408. package/dist/web/hooks/use-tool-info.d.ts +46 -14
  409. package/dist/web/hooks/use-tool-info.js +29 -7
  410. package/dist/web/hooks/use-tool-info.js.map +1 -1
  411. package/dist/web/hooks/use-tool-info.test-d.js +11 -34
  412. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  413. package/dist/web/hooks/use-tool-info.test.js +42 -37
  414. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  415. package/dist/web/hooks/use-user.d.ts +5 -2
  416. package/dist/web/hooks/use-user.js +6 -3
  417. package/dist/web/hooks/use-user.js.map +1 -1
  418. package/dist/web/hooks/use-user.test.js +85 -37
  419. package/dist/web/hooks/use-user.test.js.map +1 -1
  420. package/dist/web/hooks/use-view-state.d.ts +25 -0
  421. package/dist/web/hooks/use-view-state.js +42 -0
  422. package/dist/web/hooks/use-view-state.js.map +1 -0
  423. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  424. package/dist/web/hooks/{use-widget-state.test.js → use-view-state.test.js} +56 -21
  425. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  426. package/dist/web/hooks/use-viewport.d.ts +20 -0
  427. package/dist/web/hooks/use-viewport.js +21 -0
  428. package/dist/web/hooks/use-viewport.js.map +1 -0
  429. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  430. package/dist/web/hooks/use-viewport.test.js +109 -0
  431. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  432. package/dist/web/index.d.ts +1 -3
  433. package/dist/web/index.js +1 -2
  434. package/dist/web/index.js.map +1 -1
  435. package/dist/web/mount-view.d.ts +21 -0
  436. package/dist/web/mount-view.js +43 -0
  437. package/dist/web/mount-view.js.map +1 -0
  438. package/dist/web/proxy.js.map +1 -1
  439. package/dist/web/types.d.ts +4 -0
  440. package/dist/web/types.js.map +1 -1
  441. package/package.json +45 -28
  442. package/dist/server/templates/development.hbs +0 -12
  443. package/dist/server/templates/production.hbs +0 -6
  444. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -24
  445. package/dist/web/bridges/apps-sdk/adaptor.js +0 -87
  446. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  447. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -48
  448. package/dist/web/bridges/mcp-app/adaptor.js +0 -268
  449. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  450. package/dist/web/hooks/use-layout.d.ts +0 -22
  451. package/dist/web/hooks/use-layout.js +0 -23
  452. package/dist/web/hooks/use-layout.js.map +0 -1
  453. package/dist/web/hooks/use-layout.test.js +0 -96
  454. package/dist/web/hooks/use-layout.test.js.map +0 -1
  455. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  456. package/dist/web/hooks/use-widget-state.js +0 -32
  457. package/dist/web/hooks/use-widget-state.js.map +0 -1
  458. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  459. package/dist/web/mount-widget.d.ts +0 -1
  460. package/dist/web/mount-widget.js +0 -27
  461. package/dist/web/mount-widget.js.map +0 -1
  462. package/dist/web/plugin/data-llm.test.js +0 -81
  463. package/dist/web/plugin/data-llm.test.js.map +0 -1
  464. package/dist/web/plugin/plugin.d.ts +0 -5
  465. package/dist/web/plugin/plugin.js +0 -141
  466. package/dist/web/plugin/plugin.js.map +0 -1
  467. package/dist/web/plugin/scan-views.js.map +0 -1
  468. package/dist/web/plugin/scan-views.test.js.map +0 -1
  469. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  470. package/dist/web/plugin/transform-data-llm.js +0 -96
  471. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  472. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  473. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  474. package/dist/web/plugin/validate-view.d.ts +0 -1
  475. package/dist/web/plugin/validate-view.js.map +0 -1
  476. package/dist/web/plugin/validate-view.test.js.map +0 -1
  477. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  478. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  479. /package/dist/{web/plugin/data-llm.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  480. /package/dist/{web/plugin/scan-views.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  481. /package/dist/{web/plugin/transform-data-llm.test.d.ts → cli/tunnel.test.d.ts} +0 -0
  482. /package/dist/{web/plugin/validate-view.test.d.ts → context-warnings.test.d.ts} +0 -0
  483. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -0,0 +1,31 @@
1
+ export const TOOL_OUTPUT_WARNING_TOKENS = 5_000;
2
+ export const VIEW_STATE_WARNING_TOKENS = 20_000;
3
+ export function estimateContextTokens(value) {
4
+ try {
5
+ const serialized = JSON.stringify(value);
6
+ if (!serialized) {
7
+ return 0;
8
+ }
9
+ return Math.ceil(new TextEncoder().encode(serialized).length / 4);
10
+ }
11
+ catch {
12
+ return 0;
13
+ }
14
+ }
15
+ export function warnOnLargeToolOutput(result, toolName) {
16
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
17
+ return;
18
+ }
19
+ const { _meta, ...modelVisibleResult } = result;
20
+ const tokenCount = estimateContextTokens(modelVisibleResult);
21
+ if (tokenCount >= TOOL_OUTPUT_WARNING_TOKENS) {
22
+ console.warn(`[skybridge] Tool "${toolName}" returned ${tokenCount} estimated model-visible tokens; this reaches the ${TOOL_OUTPUT_WARNING_TOKENS}-token warning threshold and may overload model context. Content and structured content are included in this estimate.`);
23
+ }
24
+ }
25
+ export function warnOnLargeViewState(value, source) {
26
+ const tokenCount = estimateContextTokens(value);
27
+ if (tokenCount >= VIEW_STATE_WARNING_TOKENS) {
28
+ console.warn(`[skybridge] ${source} is persisting ${tokenCount} estimated tokens in model-visible view state; this reaches the ${VIEW_STATE_WARNING_TOKENS}-token warning threshold and may overload model context. Persisted view state and data-llm context are included in this estimate.`);
29
+ }
30
+ }
31
+ //# sourceMappingURL=context-warnings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-warnings.js","sourceRoot":"","sources":["../src/context-warnings.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAK,CAAC;AAChD,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAe,EAAE,QAAgB;IACrE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,OAAO;IACT,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,GAAG,kBAAkB,EAAE,GAAG,MAAiC,CAAC;IAC3E,MAAM,UAAU,GAAG,qBAAqB,CAAC,kBAAkB,CAAC,CAAC;IAC7D,IAAI,UAAU,IAAI,0BAA0B,EAAE,CAAC;QAC7C,OAAO,CAAC,IAAI,CACV,qBAAqB,QAAQ,cAAc,UAAU,qDAAqD,0BAA0B,wHAAwH,CAC7P,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAAE,MAAc;IACjE,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,UAAU,IAAI,yBAAyB,EAAE,CAAC;QAC5C,OAAO,CAAC,IAAI,CACV,eAAe,MAAM,kBAAkB,UAAU,mEAAmE,yBAAyB,mIAAmI,CACjR,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["export const TOOL_OUTPUT_WARNING_TOKENS = 5_000;\nexport const VIEW_STATE_WARNING_TOKENS = 20_000;\n\nexport function estimateContextTokens(value: unknown): number {\n try {\n const serialized = JSON.stringify(value);\n if (!serialized) {\n return 0;\n }\n return Math.ceil(new TextEncoder().encode(serialized).length / 4);\n } catch {\n return 0;\n }\n}\n\nexport function warnOnLargeToolOutput(result: unknown, toolName: string): void {\n if (!result || typeof result !== \"object\" || Array.isArray(result)) {\n return;\n }\n const { _meta, ...modelVisibleResult } = result as Record<string, unknown>;\n const tokenCount = estimateContextTokens(modelVisibleResult);\n if (tokenCount >= TOOL_OUTPUT_WARNING_TOKENS) {\n console.warn(\n `[skybridge] Tool \"${toolName}\" returned ${tokenCount} estimated model-visible tokens; this reaches the ${TOOL_OUTPUT_WARNING_TOKENS}-token warning threshold and may overload model context. Content and structured content are included in this estimate.`,\n );\n }\n}\n\nexport function warnOnLargeViewState(value: unknown, source: string): void {\n const tokenCount = estimateContextTokens(value);\n if (tokenCount >= VIEW_STATE_WARNING_TOKENS) {\n console.warn(\n `[skybridge] ${source} is persisting ${tokenCount} estimated tokens in model-visible view state; this reaches the ${VIEW_STATE_WARNING_TOKENS}-token warning threshold and may overload model context. Persisted view state and data-llm context are included in this estimate.`,\n );\n }\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { estimateContextTokens, TOOL_OUTPUT_WARNING_TOKENS, warnOnLargeToolOutput, } from "./context-warnings.js";
3
+ describe("context warnings", () => {
4
+ it("estimates UTF-8 bytes and returns zero for no content", () => {
5
+ expect(estimateContextTokens("é")).toBe(1);
6
+ expect(estimateContextTokens(undefined)).toBe(0);
7
+ });
8
+ it("warns when model-visible tool output reaches the threshold", () => {
9
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
10
+ warnOnLargeToolOutput({
11
+ content: [
12
+ {
13
+ type: "text",
14
+ text: "x".repeat(TOOL_OUTPUT_WARNING_TOKENS * 4),
15
+ },
16
+ ],
17
+ }, "large-output");
18
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Tool "large-output" returned'));
19
+ warnSpy.mockRestore();
20
+ });
21
+ it("does not warn for large metadata", () => {
22
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
23
+ warnOnLargeToolOutput({ content: [], _meta: { private: "x".repeat(100_000) } }, "large-meta");
24
+ expect(warnSpy).not.toHaveBeenCalled();
25
+ warnSpy.mockRestore();
26
+ });
27
+ });
28
+ //# sourceMappingURL=context-warnings.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-warnings.test.js","sourceRoot":"","sources":["../src/context-warnings.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEvE,qBAAqB,CACnB;YACE,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,0BAA0B,GAAG,CAAC,CAAC;iBACjD;aACF;SACF,EACD,cAAc,CACf,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAClC,MAAM,CAAC,gBAAgB,CAAC,8BAA8B,CAAC,CACxD,CAAC;QACF,OAAO,CAAC,WAAW,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEvE,qBAAqB,CACnB,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,EACxD,YAAY,CACb,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACvC,OAAO,CAAC,WAAW,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it, vi } from \"vitest\";\nimport {\n estimateContextTokens,\n TOOL_OUTPUT_WARNING_TOKENS,\n warnOnLargeToolOutput,\n} from \"./context-warnings.js\";\n\ndescribe(\"context warnings\", () => {\n it(\"estimates UTF-8 bytes and returns zero for no content\", () => {\n expect(estimateContextTokens(\"é\")).toBe(1);\n expect(estimateContextTokens(undefined)).toBe(0);\n });\n\n it(\"warns when model-visible tool output reaches the threshold\", () => {\n const warnSpy = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n\n warnOnLargeToolOutput(\n {\n content: [\n {\n type: \"text\",\n text: \"x\".repeat(TOOL_OUTPUT_WARNING_TOKENS * 4),\n },\n ],\n },\n \"large-output\",\n );\n\n expect(warnSpy).toHaveBeenCalledWith(\n expect.stringContaining('Tool \"large-output\" returned'),\n );\n warnSpy.mockRestore();\n });\n\n it(\"does not warn for large metadata\", () => {\n const warnSpy = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n\n warnOnLargeToolOutput(\n { content: [], _meta: { private: \"x\".repeat(100_000) } },\n \"large-meta\",\n );\n\n expect(warnSpy).not.toHaveBeenCalled();\n warnSpy.mockRestore();\n });\n});\n"]}
@@ -0,0 +1,175 @@
1
+ import type { Implementation, Server as SdkServer, ServerOptions } from "@modelcontextprotocol/server";
2
+ import type { ErrorRequestHandler, Express, RequestHandler } from "express";
3
+ import type { ExtraClaims } from "./auth.js";
4
+ import { McpServer, type McpServerTypes, type SkybridgeServerOptions, type ToolDef } from "./server.js";
5
+ /**
6
+ * Everything a Skybridge app needs in one bag: the MCP implementation info
7
+ * (`name`, `version`, …), the SDK's {@link ServerOptions} (`capabilities`,
8
+ * `instructions`, …), and the Skybridge-specific options (`oauth`, `json`,
9
+ * `skills`).
10
+ */
11
+ export type SkybridgeConfig<TAuthExtra extends ExtraClaims = ExtraClaims> = Implementation & ServerOptions & SkybridgeServerOptions<TAuthExtra>;
12
+ /**
13
+ * The bare {@link McpServer} a {@link SkybridgeFactory} receives: no tools
14
+ * registered yet. Use it to annotate a factory extracted into its own
15
+ * declaration — `(server: SkybridgeServer) => server.registerTool(…)` — and
16
+ * pass the claims your OAuth verifier produces to type
17
+ * `extra.http.authInfo.extra` in handlers. Leave the factory's return type
18
+ * inferred: the returned chain is what carries the tool registry into
19
+ * `typeof app`.
20
+ */
21
+ export type SkybridgeServer<TAuthExtra extends ExtraClaims = ExtraClaims> = McpServer<Record<never, ToolDef>, TAuthExtra>;
22
+ /**
23
+ * Builds an app's MCP surface. Runs again for **every incoming request**, on a
24
+ * fresh {@link McpServer}, so keep it to registration: hoist pools, timers,
25
+ * clients and any other side effect to module scope and close over them.
26
+ *
27
+ * It must **return** the chained server so `typeof app` carries the registered
28
+ * tool types.
29
+ */
30
+ export type SkybridgeFactory<TTools extends Record<string, ToolDef>, TAuthExtra extends ExtraClaims> = (server: McpServer<Record<never, ToolDef>, TAuthExtra>) => McpServer<TTools, TAuthExtra>;
31
+ /**
32
+ * Async alternative to passing a {@link SkybridgeFactory} directly: a zero-arg
33
+ * function that loads whatever the factory needs (remote config, secrets, …)
34
+ * and resolves to it. It runs once — at {@link Skybridge.run} or on the first
35
+ * request, never at module import — so importing `server.ts` from tests and
36
+ * evals stays free of side effects. The factory it returns is still
37
+ * synchronous and still runs per request.
38
+ */
39
+ export type SkybridgeFactoryLoader<TTools extends Record<string, ToolDef>, TAuthExtra extends ExtraClaims> = () => Promise<SkybridgeFactory<TTools, TAuthExtra>>;
40
+ /**
41
+ * A Skybridge app: the HTTP surface (Express, OAuth metadata, the `/mcp`
42
+ * route) plus a factory that builds the MCP server for each request.
43
+ *
44
+ * The factory runs for every request, so tools, resources, prompts and views
45
+ * are always registered on the instance that serves the request. Anything in
46
+ * the factory body other than registration therefore runs per request too.
47
+ * It also runs once up front — at construction, or as soon as an async
48
+ * loader resolves — which surfaces registration errors at boot and gives the
49
+ * OAuth layer the set of per-tool security schemes.
50
+ *
51
+ * Anything asynchronous the factory needs (remote config, secrets, …) goes in
52
+ * a {@link SkybridgeFactoryLoader} passed in its place:
53
+ * `new Skybridge(config, async () => { const cfg = await load(); return (server) => …; })`.
54
+ *
55
+ * @typeParam TTools - Accumulated tool registry, inferred from the server the
56
+ * factory returns. You almost never set this manually.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * export const app = new Skybridge(
61
+ * { name: "my-app", version: "1.0.0", capabilities: {} },
62
+ * (server) =>
63
+ * server.registerTool(
64
+ * {
65
+ * name: "search",
66
+ * inputSchema: { query: z.string() },
67
+ * view: { component: "search" },
68
+ * },
69
+ * async ({ query }) => ({ content: `Results for ${query}` }),
70
+ * ),
71
+ * );
72
+ *
73
+ * export type AppType = typeof app;
74
+ * ```
75
+ *
76
+ * @see https://docs.skybridge.tech/api-reference/mcp-server
77
+ */
78
+ export declare class Skybridge<TTools extends Record<string, ToolDef> = Record<never, ToolDef>, TAuthExtra extends ExtraClaims = ExtraClaims> {
79
+ readonly $types: McpServerTypes<TTools>;
80
+ private readonly serverInfo;
81
+ private readonly serverOptions;
82
+ private readonly skybridgeOptions;
83
+ private factory?;
84
+ private readonly factoryLoader?;
85
+ private readonly expressApp;
86
+ private readonly errorMiddleware;
87
+ private readonly monitoringEntry;
88
+ private resolveResourceMetadataUrl?;
89
+ private ready?;
90
+ private slowFactoryWarned;
91
+ constructor(config: SkybridgeConfig<TAuthExtra>, factory: SkybridgeFactory<TTools, TAuthExtra> | SkybridgeFactoryLoader<TTools, TAuthExtra>);
92
+ /**
93
+ * Resolve the factory loader and the OAuth config thunk, then wire OAuth
94
+ * onto the Express app. Runs once; every entry point that needs a built
95
+ * server awaits it. Immediate no-op when both were passed synchronously.
96
+ */
97
+ private ensureReady;
98
+ /**
99
+ * The underlying Express app. Use this to extend the HTTP server with
100
+ * custom routes, middleware, or settings — e.g.
101
+ * `app.express.get("/health", ...)`.
102
+ *
103
+ * `express.json()` is pre-applied — tune it via the `json` config field,
104
+ * e.g. `new Skybridge({ name, version, json: { limit: "10mb" } }, setup)`.
105
+ * Register your handlers before `run()`; after `run()`, dev-mode middleware,
106
+ * the `/mcp` route, and the default error handler are appended in that order.
107
+ *
108
+ * Note: Alpic Cloud only routes traffic to `/mcp` — custom routes work
109
+ * locally and on self-hosted deployments.
110
+ */
111
+ get express(): Express;
112
+ /**
113
+ * Build a fresh server for one stateless HTTP request, as
114
+ * `createMcpHandler`'s factory contract requires: the factory runs again so
115
+ * the SDK's handler closures belong to the instance whose protocol era it
116
+ * stamps. Sharing one instance's handler maps instead would bind them to an
117
+ * instance that is never marked, pinning every request to the 2025 codec and
118
+ * letting concurrent callers overwrite each other's negotiated version.
119
+ *
120
+ * Awaits the async factory loader and the lazy OAuth config on first use.
121
+ */
122
+ createServerInstance(): Promise<SdkServer>;
123
+ /**
124
+ * Connect a Skybridge app to an MCP transport. Use this when you're
125
+ * embedding Skybridge in a host that already manages its own transport
126
+ * (e.g. stdio for desktop apps); for HTTP, prefer {@link Skybridge.run}
127
+ * which sets the transport up for you.
128
+ */
129
+ connect(transport: Parameters<SdkServer["connect"]>[0]): Promise<void>;
130
+ /**
131
+ * Register Express middleware on the underlying app. Mirrors `app.use` —
132
+ * pass handlers directly or a path-prefixed handler list. Register before
133
+ * {@link Skybridge.run}; ordering matches Express.
134
+ *
135
+ * Note: Alpic Cloud only routes traffic to `/mcp`. Custom paths work
136
+ * locally and on self-hosted deployments.
137
+ */
138
+ use(...handlers: RequestHandler[]): this;
139
+ use(path: string, ...handlers: RequestHandler[]): this;
140
+ /**
141
+ * Register Express error-handling middleware to run after the built-in
142
+ * `/mcp` route (or your custom route). Use this to log or transform errors
143
+ * thrown by tool handlers before the default error handler responds.
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * app.useOnError((err, _req, _res, next) => {
148
+ * logger.error(err);
149
+ * next(err);
150
+ * });
151
+ * ```
152
+ */
153
+ useOnError(...handlers: ErrorRequestHandler[]): this;
154
+ useOnError(path: string, ...handlers: ErrorRequestHandler[]): this;
155
+ /**
156
+ * Start the HTTP server. Listens on `process.env.__PORT` (default `3000`),
157
+ * mounts the `/mcp` route, and applies any custom Express middleware
158
+ * registered via {@link Skybridge.use} / {@link Skybridge.useOnError}.
159
+ *
160
+ * On Cloudflare Workers / workerd, returns an object exposing `fetch` so
161
+ * the runtime can bridge incoming requests to the Node HTTP server. On
162
+ * Vercel (`VERCEL === "1"`), returns the Express app directly so the
163
+ * serverless function entry can call it as a `(req, res)` handler. On
164
+ * Node, returns `undefined` once listening. When the process was spawned
165
+ * with an IPC channel, the bound port is reported to the parent as
166
+ * `{ type: "skybridge:listening", port }`, the readiness signal test runners
167
+ * wait on instead of polling.
168
+ */
169
+ run(): Promise<{
170
+ fetch: (...args: unknown[]) => unknown;
171
+ } | Express | undefined>;
172
+ private buildServer;
173
+ private middlewareEntries;
174
+ private instrumentHandlers;
175
+ }
@@ -0,0 +1,275 @@
1
+ import http from "node:http";
2
+ import { setupOAuth } from "./auth/setup.js";
3
+ import { buildMcpHandler, createApp, createBaseApp } from "./express.js";
4
+ import { createMiddlewareEntry } from "./metric.js";
5
+ import { buildMiddlewareChain, getHandlerMaps } from "./middleware.js";
6
+ import { McpServer, } from "./server.js";
7
+ const SLOW_FACTORY_THRESHOLD_MS = 50;
8
+ /**
9
+ * A Skybridge app: the HTTP surface (Express, OAuth metadata, the `/mcp`
10
+ * route) plus a factory that builds the MCP server for each request.
11
+ *
12
+ * The factory runs for every request, so tools, resources, prompts and views
13
+ * are always registered on the instance that serves the request. Anything in
14
+ * the factory body other than registration therefore runs per request too.
15
+ * It also runs once up front — at construction, or as soon as an async
16
+ * loader resolves — which surfaces registration errors at boot and gives the
17
+ * OAuth layer the set of per-tool security schemes.
18
+ *
19
+ * Anything asynchronous the factory needs (remote config, secrets, …) goes in
20
+ * a {@link SkybridgeFactoryLoader} passed in its place:
21
+ * `new Skybridge(config, async () => { const cfg = await load(); return (server) => …; })`.
22
+ *
23
+ * @typeParam TTools - Accumulated tool registry, inferred from the server the
24
+ * factory returns. You almost never set this manually.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * export const app = new Skybridge(
29
+ * { name: "my-app", version: "1.0.0", capabilities: {} },
30
+ * (server) =>
31
+ * server.registerTool(
32
+ * {
33
+ * name: "search",
34
+ * inputSchema: { query: z.string() },
35
+ * view: { component: "search" },
36
+ * },
37
+ * async ({ query }) => ({ content: `Results for ${query}` }),
38
+ * ),
39
+ * );
40
+ *
41
+ * export type AppType = typeof app;
42
+ * ```
43
+ *
44
+ * @see https://docs.skybridge.tech/api-reference/mcp-server
45
+ */
46
+ export class Skybridge {
47
+ serverInfo;
48
+ serverOptions;
49
+ skybridgeOptions;
50
+ factory;
51
+ factoryLoader;
52
+ expressApp;
53
+ errorMiddleware = [];
54
+ monitoringEntry = createMiddlewareEntry();
55
+ resolveResourceMetadataUrl;
56
+ ready;
57
+ slowFactoryWarned = false;
58
+ constructor(config, factory) {
59
+ const { name, title, version, description, icons, websiteUrl, json, oauth, skills, ...serverOptions } = config;
60
+ this.serverInfo = { name, title, version, description, icons, websiteUrl };
61
+ this.serverOptions = serverOptions;
62
+ this.skybridgeOptions = { json, oauth, skills };
63
+ this.expressApp = createBaseApp(json);
64
+ if (factory.length === 0) {
65
+ this.factoryLoader = factory;
66
+ return;
67
+ }
68
+ this.factory = factory;
69
+ if (typeof oauth === "function") {
70
+ return;
71
+ }
72
+ const sample = this.buildServer();
73
+ if (oauth) {
74
+ this.resolveResourceMetadataUrl = setupOAuth(this.expressApp, oauth, sample.securitySchemesByTool);
75
+ }
76
+ this.ready = Promise.resolve();
77
+ }
78
+ /**
79
+ * Resolve the factory loader and the OAuth config thunk, then wire OAuth
80
+ * onto the Express app. Runs once; every entry point that needs a built
81
+ * server awaits it. Immediate no-op when both were passed synchronously.
82
+ */
83
+ ensureReady() {
84
+ this.ready ??= (async () => {
85
+ if (this.factoryLoader) {
86
+ this.factory = await this.factoryLoader();
87
+ }
88
+ const { oauth } = this.skybridgeOptions;
89
+ const resolvedOauth = typeof oauth === "function" ? await oauth() : oauth;
90
+ const sample = this.buildServer();
91
+ if (resolvedOauth) {
92
+ this.resolveResourceMetadataUrl = setupOAuth(this.expressApp, resolvedOauth, sample.securitySchemesByTool);
93
+ }
94
+ })().catch((error) => {
95
+ this.ready = undefined;
96
+ throw error;
97
+ });
98
+ return this.ready;
99
+ }
100
+ /**
101
+ * The underlying Express app. Use this to extend the HTTP server with
102
+ * custom routes, middleware, or settings — e.g.
103
+ * `app.express.get("/health", ...)`.
104
+ *
105
+ * `express.json()` is pre-applied — tune it via the `json` config field,
106
+ * e.g. `new Skybridge({ name, version, json: { limit: "10mb" } }, setup)`.
107
+ * Register your handlers before `run()`; after `run()`, dev-mode middleware,
108
+ * the `/mcp` route, and the default error handler are appended in that order.
109
+ *
110
+ * Note: Alpic Cloud only routes traffic to `/mcp` — custom routes work
111
+ * locally and on self-hosted deployments.
112
+ */
113
+ get express() {
114
+ return this.expressApp;
115
+ }
116
+ /**
117
+ * Build a fresh server for one stateless HTTP request, as
118
+ * `createMcpHandler`'s factory contract requires: the factory runs again so
119
+ * the SDK's handler closures belong to the instance whose protocol era it
120
+ * stamps. Sharing one instance's handler maps instead would bind them to an
121
+ * instance that is never marked, pinning every request to the 2025 codec and
122
+ * letting concurrent callers overwrite each other's negotiated version.
123
+ *
124
+ * Awaits the async factory loader and the lazy OAuth config on first use.
125
+ */
126
+ async createServerInstance() {
127
+ await this.ensureReady();
128
+ const server = this.buildServer();
129
+ this.instrumentHandlers(server);
130
+ return server.server;
131
+ }
132
+ /**
133
+ * Connect a Skybridge app to an MCP transport. Use this when you're
134
+ * embedding Skybridge in a host that already manages its own transport
135
+ * (e.g. stdio for desktop apps); for HTTP, prefer {@link Skybridge.run}
136
+ * which sets the transport up for you.
137
+ */
138
+ async connect(transport) {
139
+ const instance = await this.createServerInstance();
140
+ await instance.connect(transport);
141
+ }
142
+ use(pathOrHandler, ...handlers) {
143
+ // Branching is load-bearing: Express's `app.use` overloads can't be
144
+ // resolved against a `string | RequestHandler` union, so we narrow.
145
+ if (typeof pathOrHandler === "string") {
146
+ this.expressApp.use(pathOrHandler, ...handlers);
147
+ }
148
+ else {
149
+ this.expressApp.use(pathOrHandler, ...handlers);
150
+ }
151
+ return this;
152
+ }
153
+ useOnError(pathOrHandler, ...handlers) {
154
+ if (typeof pathOrHandler === "string") {
155
+ this.errorMiddleware.push({ path: pathOrHandler, handlers });
156
+ }
157
+ else {
158
+ this.errorMiddleware.push({ handlers: [pathOrHandler, ...handlers] });
159
+ }
160
+ return this;
161
+ }
162
+ /**
163
+ * Start the HTTP server. Listens on `process.env.__PORT` (default `3000`),
164
+ * mounts the `/mcp` route, and applies any custom Express middleware
165
+ * registered via {@link Skybridge.use} / {@link Skybridge.useOnError}.
166
+ *
167
+ * On Cloudflare Workers / workerd, returns an object exposing `fetch` so
168
+ * the runtime can bridge incoming requests to the Node HTTP server. On
169
+ * Vercel (`VERCEL === "1"`), returns the Express app directly so the
170
+ * serverless function entry can call it as a `(req, res)` handler. On
171
+ * Node, returns `undefined` once listening. When the process was spawned
172
+ * with an IPC channel, the bound port is reported to the parent as
173
+ * `{ type: "skybridge:listening", port }`, the readiness signal test runners
174
+ * wait on instead of polling.
175
+ */
176
+ async run() {
177
+ await this.ensureReady();
178
+ if (process.env.VERCEL === "1") {
179
+ // createApp only reads httpServer inside its dev-only branch
180
+ // (viewsDevServer); under VERCEL=1 + NODE_ENV=production it's a
181
+ // bare object passed to satisfy the required parameter.
182
+ const httpServer = http.createServer();
183
+ await createApp({
184
+ app: this,
185
+ httpServer,
186
+ errorMiddleware: this.errorMiddleware,
187
+ });
188
+ return this.expressApp;
189
+ }
190
+ const httpServer = http.createServer();
191
+ const mcpHandler = buildMcpHandler(this);
192
+ await createApp({
193
+ app: this,
194
+ httpServer,
195
+ mcpHandler,
196
+ errorMiddleware: this.errorMiddleware,
197
+ });
198
+ httpServer.on("request", this.expressApp);
199
+ const intendedPort = parseInt(process.env.__PORT ?? "3000", 10);
200
+ await new Promise((resolve, reject) => {
201
+ httpServer.on("error", (error) => {
202
+ console.error("Failed to start server:", error);
203
+ reject(error);
204
+ });
205
+ httpServer.listen(intendedPort, () => {
206
+ resolve();
207
+ });
208
+ });
209
+ const { port } = httpServer.address();
210
+ process.send?.({ type: "skybridge:listening", port });
211
+ // On workerd, bridge the Node http server to a Workers fetch handler.
212
+ // The specifier is held in a variable to sidestep tsc's module resolution
213
+ // (`cloudflare:node` only exists under wrangler/workerd).
214
+ if (typeof navigator !== "undefined" &&
215
+ navigator.userAgent === "Cloudflare-Workers") {
216
+ const cloudflareNode = "cloudflare:node";
217
+ const { httpServerHandler } = await import(cloudflareNode);
218
+ return httpServerHandler({ port });
219
+ }
220
+ const shutdown = () => {
221
+ // Drop both handlers so a second signal falls through to Node's default
222
+ // (force-quit on a second Ctrl+C while drain is hanging).
223
+ process.off("SIGTERM", shutdown);
224
+ process.off("SIGINT", shutdown);
225
+ mcpHandler.close().catch(() => { });
226
+ httpServer.close(() => process.exit(0));
227
+ // Force exit if connections don't drain in time so the port is still
228
+ // released promptly (e.g. for nodemon restarts).
229
+ setTimeout(() => process.exit(0), 3000).unref();
230
+ };
231
+ process.on("SIGTERM", shutdown);
232
+ process.on("SIGINT", shutdown);
233
+ return undefined;
234
+ }
235
+ buildServer() {
236
+ if (!this.factory) {
237
+ throw new Error("Skybridge factory not loaded yet: this app was constructed with an async factory loader. Await run(), connect(), or createServerInstance().");
238
+ }
239
+ const server = new McpServer(this.serverInfo, this.serverOptions, this.skybridgeOptions);
240
+ if (this.resolveResourceMetadataUrl) {
241
+ server.setResourceMetadataUrlResolver(this.resolveResourceMetadataUrl);
242
+ }
243
+ const startedAt = performance.now();
244
+ const built = this.factory(server);
245
+ const elapsed = performance.now() - startedAt;
246
+ if (typeof built.then === "function") {
247
+ throw new Error("The Skybridge factory must be synchronous — it runs on every request. To load config or secrets asynchronously, pass a loader instead: new Skybridge(config, async () => factory).");
248
+ }
249
+ if (elapsed > SLOW_FACTORY_THRESHOLD_MS && !this.slowFactoryWarned) {
250
+ this.slowFactoryWarned = true;
251
+ console.warn(`The Skybridge factory took ${Math.round(elapsed)}ms — it runs on every request, so this cost is paid per request. Hoist expensive work to module scope, or move awaited setup into an async loader: new Skybridge(config, async () => factory).`);
252
+ }
253
+ return built;
254
+ }
255
+ middlewareEntries(server) {
256
+ return [
257
+ ...(this.monitoringEntry ? [this.monitoringEntry] : []),
258
+ ...server.protocolMiddlewareEntries(),
259
+ ];
260
+ }
261
+ instrumentHandlers(server) {
262
+ const entries = this.middlewareEntries(server);
263
+ const { requestHandlers, notificationHandlers } = getHandlerMaps(server.server);
264
+ const instrumentMap = (map, isNotification) => {
265
+ for (const [method, handler] of map) {
266
+ map.set(method, buildMiddlewareChain(method, isNotification, handler, entries));
267
+ }
268
+ const originalSet = map.set.bind(map);
269
+ map.set = (method, handler) => originalSet(method, buildMiddlewareChain(method, isNotification, handler, entries));
270
+ };
271
+ instrumentMap(requestHandlers, false);
272
+ instrumentMap(notificationHandlers, true);
273
+ }
274
+ }
275
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":"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","sourcesContent":["import http from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport type {\n Implementation,\n Server as SdkServer,\n ServerOptions,\n} from \"@modelcontextprotocol/server\";\nimport type { ErrorRequestHandler, Express, RequestHandler } from \"express\";\nimport { type ResourceMetadataUrlResolver, setupOAuth } from \"./auth/setup.js\";\nimport type { ExtraClaims } from \"./auth.js\";\nimport { buildMcpHandler, createApp, createBaseApp } from \"./express.js\";\nimport { createMiddlewareEntry } from \"./metric.js\";\nimport type { McpMiddlewareEntry } from \"./middleware.js\";\nimport { buildMiddlewareChain, getHandlerMaps } from \"./middleware.js\";\nimport {\n McpServer,\n type McpServerTypes,\n type SkybridgeServerOptions,\n type ToolDef,\n} from \"./server.js\";\n\nconst SLOW_FACTORY_THRESHOLD_MS = 50;\n\ntype ErrorMiddlewareConfig = {\n path?: string;\n handlers: ErrorRequestHandler[];\n};\n\n/**\n * Everything a Skybridge app needs in one bag: the MCP implementation info\n * (`name`, `version`, …), the SDK's {@link ServerOptions} (`capabilities`,\n * `instructions`, …), and the Skybridge-specific options (`oauth`, `json`,\n * `skills`).\n */\nexport type SkybridgeConfig<TAuthExtra extends ExtraClaims = ExtraClaims> =\n Implementation & ServerOptions & SkybridgeServerOptions<TAuthExtra>;\n\n/**\n * The bare {@link McpServer} a {@link SkybridgeFactory} receives: no tools\n * registered yet. Use it to annotate a factory extracted into its own\n * declaration — `(server: SkybridgeServer) => server.registerTool(…)` — and\n * pass the claims your OAuth verifier produces to type\n * `extra.http.authInfo.extra` in handlers. Leave the factory's return type\n * inferred: the returned chain is what carries the tool registry into\n * `typeof app`.\n */\nexport type SkybridgeServer<TAuthExtra extends ExtraClaims = ExtraClaims> =\n McpServer<Record<never, ToolDef>, TAuthExtra>;\n\n/**\n * Builds an app's MCP surface. Runs again for **every incoming request**, on a\n * fresh {@link McpServer}, so keep it to registration: hoist pools, timers,\n * clients and any other side effect to module scope and close over them.\n *\n * It must **return** the chained server so `typeof app` carries the registered\n * tool types.\n */\nexport type SkybridgeFactory<\n TTools extends Record<string, ToolDef>,\n TAuthExtra extends ExtraClaims,\n> = (\n server: McpServer<Record<never, ToolDef>, TAuthExtra>,\n) => McpServer<TTools, TAuthExtra>;\n\n/**\n * Async alternative to passing a {@link SkybridgeFactory} directly: a zero-arg\n * function that loads whatever the factory needs (remote config, secrets, …)\n * and resolves to it. It runs once — at {@link Skybridge.run} or on the first\n * request, never at module import — so importing `server.ts` from tests and\n * evals stays free of side effects. The factory it returns is still\n * synchronous and still runs per request.\n */\nexport type SkybridgeFactoryLoader<\n TTools extends Record<string, ToolDef>,\n TAuthExtra extends ExtraClaims,\n> = () => Promise<SkybridgeFactory<TTools, TAuthExtra>>;\n\n/**\n * A Skybridge app: the HTTP surface (Express, OAuth metadata, the `/mcp`\n * route) plus a factory that builds the MCP server for each request.\n *\n * The factory runs for every request, so tools, resources, prompts and views\n * are always registered on the instance that serves the request. Anything in\n * the factory body other than registration therefore runs per request too.\n * It also runs once up front — at construction, or as soon as an async\n * loader resolves — which surfaces registration errors at boot and gives the\n * OAuth layer the set of per-tool security schemes.\n *\n * Anything asynchronous the factory needs (remote config, secrets, …) goes in\n * a {@link SkybridgeFactoryLoader} passed in its place:\n * `new Skybridge(config, async () => { const cfg = await load(); return (server) => …; })`.\n *\n * @typeParam TTools - Accumulated tool registry, inferred from the server the\n * factory returns. You almost never set this manually.\n *\n * @example\n * ```ts\n * export const app = new Skybridge(\n * { name: \"my-app\", version: \"1.0.0\", capabilities: {} },\n * (server) =>\n * server.registerTool(\n * {\n * name: \"search\",\n * inputSchema: { query: z.string() },\n * view: { component: \"search\" },\n * },\n * async ({ query }) => ({ content: `Results for ${query}` }),\n * ),\n * );\n *\n * export type AppType = typeof app;\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/mcp-server\n */\nexport class Skybridge<\n TTools extends Record<string, ToolDef> = Record<never, ToolDef>,\n TAuthExtra extends ExtraClaims = ExtraClaims,\n> {\n declare readonly $types: McpServerTypes<TTools>;\n private readonly serverInfo: Implementation;\n private readonly serverOptions: ServerOptions;\n private readonly skybridgeOptions: SkybridgeServerOptions<TAuthExtra>;\n private factory?: SkybridgeFactory<TTools, TAuthExtra>;\n private readonly factoryLoader?: SkybridgeFactoryLoader<TTools, TAuthExtra>;\n private readonly expressApp: Express;\n private readonly errorMiddleware: ErrorMiddlewareConfig[] = [];\n private readonly monitoringEntry: McpMiddlewareEntry | null =\n createMiddlewareEntry();\n private resolveResourceMetadataUrl?: ResourceMetadataUrlResolver;\n private ready?: Promise<void>;\n private slowFactoryWarned = false;\n\n constructor(\n config: SkybridgeConfig<TAuthExtra>,\n factory:\n | SkybridgeFactory<TTools, TAuthExtra>\n | SkybridgeFactoryLoader<TTools, TAuthExtra>,\n ) {\n const {\n name,\n title,\n version,\n description,\n icons,\n websiteUrl,\n json,\n oauth,\n skills,\n ...serverOptions\n } = config;\n\n this.serverInfo = { name, title, version, description, icons, websiteUrl };\n this.serverOptions = serverOptions;\n this.skybridgeOptions = { json, oauth, skills };\n this.expressApp = createBaseApp(json);\n\n if (factory.length === 0) {\n this.factoryLoader = factory as SkybridgeFactoryLoader<\n TTools,\n TAuthExtra\n >;\n return;\n }\n this.factory = factory as SkybridgeFactory<TTools, TAuthExtra>;\n\n if (typeof oauth === \"function\") {\n return;\n }\n\n const sample = this.buildServer();\n if (oauth) {\n this.resolveResourceMetadataUrl = setupOAuth(\n this.expressApp,\n oauth,\n sample.securitySchemesByTool,\n );\n }\n this.ready = Promise.resolve();\n }\n\n /**\n * Resolve the factory loader and the OAuth config thunk, then wire OAuth\n * onto the Express app. Runs once; every entry point that needs a built\n * server awaits it. Immediate no-op when both were passed synchronously.\n */\n private ensureReady(): Promise<void> {\n this.ready ??= (async () => {\n if (this.factoryLoader) {\n this.factory = await this.factoryLoader();\n }\n const { oauth } = this.skybridgeOptions;\n const resolvedOauth = typeof oauth === \"function\" ? await oauth() : oauth;\n const sample = this.buildServer();\n if (resolvedOauth) {\n this.resolveResourceMetadataUrl = setupOAuth(\n this.expressApp,\n resolvedOauth,\n sample.securitySchemesByTool,\n );\n }\n })().catch((error) => {\n this.ready = undefined;\n throw error;\n });\n return this.ready;\n }\n\n /**\n * The underlying Express app. Use this to extend the HTTP server with\n * custom routes, middleware, or settings — e.g.\n * `app.express.get(\"/health\", ...)`.\n *\n * `express.json()` is pre-applied — tune it via the `json` config field,\n * e.g. `new Skybridge({ name, version, json: { limit: \"10mb\" } }, setup)`.\n * Register your handlers before `run()`; after `run()`, dev-mode middleware,\n * the `/mcp` route, and the default error handler are appended in that order.\n *\n * Note: Alpic Cloud only routes traffic to `/mcp` — custom routes work\n * locally and on self-hosted deployments.\n */\n get express(): Express {\n return this.expressApp;\n }\n\n /**\n * Build a fresh server for one stateless HTTP request, as\n * `createMcpHandler`'s factory contract requires: the factory runs again so\n * the SDK's handler closures belong to the instance whose protocol era it\n * stamps. Sharing one instance's handler maps instead would bind them to an\n * instance that is never marked, pinning every request to the 2025 codec and\n * letting concurrent callers overwrite each other's negotiated version.\n *\n * Awaits the async factory loader and the lazy OAuth config on first use.\n */\n async createServerInstance(): Promise<SdkServer> {\n await this.ensureReady();\n const server = this.buildServer();\n this.instrumentHandlers(server);\n return server.server;\n }\n\n /**\n * Connect a Skybridge app to an MCP transport. Use this when you're\n * embedding Skybridge in a host that already manages its own transport\n * (e.g. stdio for desktop apps); for HTTP, prefer {@link Skybridge.run}\n * which sets the transport up for you.\n */\n async connect(transport: Parameters<SdkServer[\"connect\"]>[0]): Promise<void> {\n const instance = await this.createServerInstance();\n await instance.connect(transport);\n }\n\n /**\n * Register Express middleware on the underlying app. Mirrors `app.use` —\n * pass handlers directly or a path-prefixed handler list. Register before\n * {@link Skybridge.run}; ordering matches Express.\n *\n * Note: Alpic Cloud only routes traffic to `/mcp`. Custom paths work\n * locally and on self-hosted deployments.\n */\n use(...handlers: RequestHandler[]): this;\n use(path: string, ...handlers: RequestHandler[]): this;\n use(\n pathOrHandler: string | RequestHandler,\n ...handlers: RequestHandler[]\n ): this {\n // Branching is load-bearing: Express's `app.use` overloads can't be\n // resolved against a `string | RequestHandler` union, so we narrow.\n if (typeof pathOrHandler === \"string\") {\n this.expressApp.use(pathOrHandler, ...handlers);\n } else {\n this.expressApp.use(pathOrHandler, ...handlers);\n }\n return this;\n }\n\n /**\n * Register Express error-handling middleware to run after the built-in\n * `/mcp` route (or your custom route). Use this to log or transform errors\n * thrown by tool handlers before the default error handler responds.\n *\n * @example\n * ```ts\n * app.useOnError((err, _req, _res, next) => {\n * logger.error(err);\n * next(err);\n * });\n * ```\n */\n useOnError(...handlers: ErrorRequestHandler[]): this;\n useOnError(path: string, ...handlers: ErrorRequestHandler[]): this;\n useOnError(\n pathOrHandler: string | ErrorRequestHandler,\n ...handlers: ErrorRequestHandler[]\n ): this {\n if (typeof pathOrHandler === \"string\") {\n this.errorMiddleware.push({ path: pathOrHandler, handlers });\n } else {\n this.errorMiddleware.push({ handlers: [pathOrHandler, ...handlers] });\n }\n return this;\n }\n\n /**\n * Start the HTTP server. Listens on `process.env.__PORT` (default `3000`),\n * mounts the `/mcp` route, and applies any custom Express middleware\n * registered via {@link Skybridge.use} / {@link Skybridge.useOnError}.\n *\n * On Cloudflare Workers / workerd, returns an object exposing `fetch` so\n * the runtime can bridge incoming requests to the Node HTTP server. On\n * Vercel (`VERCEL === \"1\"`), returns the Express app directly so the\n * serverless function entry can call it as a `(req, res)` handler. On\n * Node, returns `undefined` once listening. When the process was spawned\n * with an IPC channel, the bound port is reported to the parent as\n * `{ type: \"skybridge:listening\", port }`, the readiness signal test runners\n * wait on instead of polling.\n */\n async run(): Promise<\n { fetch: (...args: unknown[]) => unknown } | Express | undefined\n > {\n await this.ensureReady();\n\n if (process.env.VERCEL === \"1\") {\n // createApp only reads httpServer inside its dev-only branch\n // (viewsDevServer); under VERCEL=1 + NODE_ENV=production it's a\n // bare object passed to satisfy the required parameter.\n const httpServer = http.createServer();\n await createApp({\n app: this,\n httpServer,\n errorMiddleware: this.errorMiddleware,\n });\n return this.expressApp;\n }\n\n const httpServer = http.createServer();\n const mcpHandler = buildMcpHandler(this);\n\n await createApp({\n app: this,\n httpServer,\n mcpHandler,\n errorMiddleware: this.errorMiddleware,\n });\n\n httpServer.on(\"request\", this.expressApp);\n const intendedPort = parseInt(process.env.__PORT ?? \"3000\", 10);\n await new Promise<void>((resolve, reject) => {\n httpServer.on(\"error\", (error: Error) => {\n console.error(\"Failed to start server:\", error);\n reject(error);\n });\n httpServer.listen(intendedPort, () => {\n resolve();\n });\n });\n\n const { port } = httpServer.address() as AddressInfo;\n process.send?.({ type: \"skybridge:listening\", port });\n\n // On workerd, bridge the Node http server to a Workers fetch handler.\n // The specifier is held in a variable to sidestep tsc's module resolution\n // (`cloudflare:node` only exists under wrangler/workerd).\n if (\n typeof navigator !== \"undefined\" &&\n navigator.userAgent === \"Cloudflare-Workers\"\n ) {\n const cloudflareNode = \"cloudflare:node\";\n const { httpServerHandler } = await import(cloudflareNode);\n return httpServerHandler({ port });\n }\n\n const shutdown = () => {\n // Drop both handlers so a second signal falls through to Node's default\n // (force-quit on a second Ctrl+C while drain is hanging).\n process.off(\"SIGTERM\", shutdown);\n process.off(\"SIGINT\", shutdown);\n mcpHandler.close().catch(() => {});\n httpServer.close(() => process.exit(0));\n // Force exit if connections don't drain in time so the port is still\n // released promptly (e.g. for nodemon restarts).\n setTimeout(() => process.exit(0), 3000).unref();\n };\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n return undefined;\n }\n\n private buildServer(): McpServer<TTools, TAuthExtra> {\n if (!this.factory) {\n throw new Error(\n \"Skybridge factory not loaded yet: this app was constructed with an async factory loader. Await run(), connect(), or createServerInstance().\",\n );\n }\n const server = new McpServer<Record<never, ToolDef>, TAuthExtra>(\n this.serverInfo,\n this.serverOptions,\n this.skybridgeOptions,\n );\n if (this.resolveResourceMetadataUrl) {\n server.setResourceMetadataUrlResolver(this.resolveResourceMetadataUrl);\n }\n const startedAt = performance.now();\n const built = this.factory(server);\n const elapsed = performance.now() - startedAt;\n if (typeof (built as { then?: unknown }).then === \"function\") {\n throw new Error(\n \"The Skybridge factory must be synchronous — it runs on every request. To load config or secrets asynchronously, pass a loader instead: new Skybridge(config, async () => factory).\",\n );\n }\n if (elapsed > SLOW_FACTORY_THRESHOLD_MS && !this.slowFactoryWarned) {\n this.slowFactoryWarned = true;\n console.warn(\n `The Skybridge factory took ${Math.round(elapsed)}ms — it runs on every request, so this cost is paid per request. Hoist expensive work to module scope, or move awaited setup into an async loader: new Skybridge(config, async () => factory).`,\n );\n }\n return built;\n }\n\n private middlewareEntries(\n server: McpServer<Record<never, ToolDef>, TAuthExtra>,\n ): McpMiddlewareEntry[] {\n return [\n ...(this.monitoringEntry ? [this.monitoringEntry] : []),\n ...server.protocolMiddlewareEntries(),\n ];\n }\n\n private instrumentHandlers(\n server: McpServer<Record<never, ToolDef>, TAuthExtra>,\n ): void {\n const entries = this.middlewareEntries(server);\n const { requestHandlers, notificationHandlers } = getHandlerMaps(\n server.server,\n );\n\n const instrumentMap = (\n map: Map<string, (...args: unknown[]) => Promise<unknown>>,\n isNotification: boolean,\n ) => {\n for (const [method, handler] of map) {\n map.set(\n method,\n buildMiddlewareChain(method, isNotification, handler, entries),\n );\n }\n const originalSet = map.set.bind(map);\n map.set = (\n method: string,\n handler: (...args: unknown[]) => Promise<unknown>,\n ) =>\n originalSet(\n method,\n buildMiddlewareChain(method, isNotification, handler, entries),\n );\n };\n\n instrumentMap(requestHandlers, false);\n instrumentMap(notificationHandlers, true);\n }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { Plugin } from "vite";
2
+ export declare function isCssRequest(id: string): boolean;
2
3
  /**
3
4
  * Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,
4
5
  * so they work both locally and behind tunnels.
@@ -1,9 +1,16 @@
1
+ // Mirrors Vite's own `isCSSRequest`: matches the css family of extensions
2
+ // either at the end of the id or right before the query string. Catches both
3
+ // plain `.css` requests and SFC style blocks (e.g. `Foo.vue?vue&type=style&lang.css`).
4
+ const CSS_LANGS_RE = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
5
+ export function isCssRequest(id) {
6
+ return CSS_LANGS_RE.test(id);
7
+ }
1
8
  /**
2
9
  * Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,
3
10
  * so they work both locally and behind tunnels.
4
11
  */
5
12
  export function assetBaseUrlTransform(code) {
6
- const assetStringPattern = /(?<!https?:\/\/)(["'`])(\/[^"'`]+\.(svg|png|jpeg|jpg|gif|webp|mp3|mp4|woff|woff2|ttf|eot))\1/g;
13
+ const assetStringPattern = /(?<!\bfrom\s)(?<!https?:\/\/)(["'`])(\/[^"'`]+\.(svg|png|jpeg|jpg|gif|webp|mp3|mp4|woff|woff2|ttf|eot))\1/g;
7
14
  code = code.replace(assetStringPattern, (_match, _quote, assetPath) => {
8
15
  return `(window.skybridge?.serverUrl ?? "") + "${assetPath}"`;
9
16
  });
@@ -15,10 +22,18 @@ export function assetBaseUrlTransform(code) {
15
22
  export function assetBaseUrlTransformPlugin() {
16
23
  return {
17
24
  name: "asset-base-url-transform",
18
- transform(code) {
25
+ transform(code, id) {
19
26
  if (!code) {
20
27
  return null;
21
28
  }
29
+ // Vite serves CSS modules as JS that embeds the stylesheet as a string
30
+ // literal. Rewriting `url("/foo.woff2")` inside that string to a JS
31
+ // concatenation expression produces invalid CSS once it lands in a
32
+ // <style> tag. CSS asset URLs are already handled at build time by
33
+ // `experimental.renderBuiltUrl`, so skip CSS requests here.
34
+ if (isCssRequest(id)) {
35
+ return null;
36
+ }
22
37
  const transformedCode = assetBaseUrlTransform(code);
23
38
  if (transformedCode === code) {
24
39
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"asset-base-url-transform-plugin.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,kBAAkB,GACtB,+FAA+F,CAAC;IAElG,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;QACpE,OAAO,0CAA0C,SAAS,GAAG,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,SAAS,CAAC,IAAI;YACZ,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAEpD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,eAAe;gBACrB,GAAG,EAAE,IAAI;aACV,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"asset-base-url-transform-plugin.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,6EAA6E;AAC7E,uFAAuF;AACvF,MAAM,YAAY,GAChB,6DAA6D,CAAC;AAEhE,MAAM,UAAU,YAAY,CAAC,EAAU;IACrC,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,kBAAkB,GACtB,4GAA4G,CAAC;IAE/G,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;QACpE,OAAO,0CAA0C,SAAS,GAAG,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,SAAS,CAAC,IAAI,EAAE,EAAE;YAChB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;YAED,uEAAuE;YACvE,oEAAoE;YACpE,mEAAmE;YACnE,mEAAmE;YACnE,4DAA4D;YAC5D,IAAI,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC;gBACrB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAEpD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,eAAe;gBACrB,GAAG,EAAE,IAAI;aACV,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Plugin } from \"vite\";\n\n// Mirrors Vite's own `isCSSRequest`: matches the css family of extensions\n// either at the end of the id or right before the query string. Catches both\n// plain `.css` requests and SFC style blocks (e.g. `Foo.vue?vue&type=style&lang.css`).\nconst CSS_LANGS_RE =\n /\\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\\?)/;\n\nexport function isCssRequest(id: string): boolean {\n return CSS_LANGS_RE.test(id);\n}\n\n/**\n * Transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`,\n * so they work both locally and behind tunnels.\n */\nexport function assetBaseUrlTransform(code: string): string {\n const assetStringPattern =\n /(?<!\\bfrom\\s)(?<!https?:\\/\\/)([\"'`])(\\/[^\"'`]+\\.(svg|png|jpeg|jpg|gif|webp|mp3|mp4|woff|woff2|ttf|eot))\\1/g;\n\n code = code.replace(assetStringPattern, (_match, _quote, assetPath) => {\n return `(window.skybridge?.serverUrl ?? \"\") + \"${assetPath}\"`;\n });\n\n return code;\n}\n\n/**\n * Vite plugin that transforms asset import paths to resolve at runtime via `window.skybridge.serverUrl`.\n */\nexport function assetBaseUrlTransformPlugin(): Plugin {\n return {\n name: \"asset-base-url-transform\",\n transform(code, id) {\n if (!code) {\n return null;\n }\n\n // Vite serves CSS modules as JS that embeds the stylesheet as a string\n // literal. Rewriting `url(\"/foo.woff2\")` inside that string to a JS\n // concatenation expression produces invalid CSS once it lands in a\n // <style> tag. CSS asset URLs are already handled at build time by\n // `experimental.renderBuiltUrl`, so skip CSS requests here.\n if (isCssRequest(id)) {\n return null;\n }\n\n const transformedCode = assetBaseUrlTransform(code);\n\n if (transformedCode === code) {\n return null;\n }\n\n return {\n code: transformedCode,\n map: null,\n };\n },\n };\n}\n"]}