skybridge 0.0.0-dev.bfd4e8f → 0.0.0-dev.bfdcccb

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 (519) 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 +1 -1
  17. package/dist/cli/header.js.map +1 -1
  18. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  19. package/dist/cli/resolve-skybridge-config.js +18 -0
  20. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  21. package/dist/cli/run-command.js.map +1 -1
  22. package/dist/cli/run-plain.d.ts +18 -0
  23. package/dist/cli/run-plain.js +90 -0
  24. package/dist/cli/run-plain.js.map +1 -0
  25. package/dist/cli/telemetry.js +2 -0
  26. package/dist/cli/telemetry.js.map +1 -1
  27. package/dist/cli/tunnel-control-server.d.ts +9 -0
  28. package/dist/cli/tunnel-control-server.js +31 -0
  29. package/dist/cli/tunnel-control-server.js.map +1 -0
  30. package/dist/cli/tunnel-control-server.test.js +39 -0
  31. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  32. package/dist/cli/tunnel-handler.d.ts +3 -0
  33. package/dist/cli/tunnel-handler.js +48 -0
  34. package/dist/cli/tunnel-handler.js.map +1 -0
  35. package/dist/cli/tunnel-handler.test.js +105 -0
  36. package/dist/cli/tunnel-handler.test.js.map +1 -0
  37. package/dist/cli/tunnel.d.ts +57 -0
  38. package/dist/cli/tunnel.js +154 -0
  39. package/dist/cli/tunnel.js.map +1 -0
  40. package/dist/cli/tunnel.test.js +190 -0
  41. package/dist/cli/tunnel.test.js.map +1 -0
  42. package/dist/cli/types.js.map +1 -1
  43. package/dist/cli/use-execute-steps.d.ts +1 -1
  44. package/dist/cli/use-execute-steps.js.map +1 -1
  45. package/dist/cli/use-messages.d.ts +3 -0
  46. package/dist/cli/use-messages.js +11 -0
  47. package/dist/cli/use-messages.js.map +1 -0
  48. package/dist/cli/use-nodemon.d.ts +26 -2
  49. package/dist/cli/use-nodemon.js +97 -71
  50. package/dist/cli/use-nodemon.js.map +1 -1
  51. package/dist/cli/use-open-browser.d.ts +1 -0
  52. package/dist/cli/use-open-browser.js +44 -0
  53. package/dist/cli/use-open-browser.js.map +1 -0
  54. package/dist/cli/use-tunnel.d.ts +13 -7
  55. package/dist/cli/use-tunnel.js +103 -73
  56. package/dist/cli/use-tunnel.js.map +1 -1
  57. package/dist/cli/use-typescript-check.d.ts +9 -2
  58. package/dist/cli/use-typescript-check.js +89 -51
  59. package/dist/cli/use-typescript-check.js.map +1 -1
  60. package/dist/commands/build.d.ts +0 -3
  61. package/dist/commands/build.js +3 -18
  62. package/dist/commands/build.js.map +1 -1
  63. package/dist/commands/create.d.ts +9 -0
  64. package/dist/commands/create.js +30 -0
  65. package/dist/commands/create.js.map +1 -0
  66. package/dist/commands/dev.d.ts +3 -0
  67. package/dist/commands/dev.js +92 -7
  68. package/dist/commands/dev.js.map +1 -1
  69. package/dist/commands/start.js +13 -10
  70. package/dist/commands/start.js.map +1 -1
  71. package/dist/commands/telemetry/disable.js.map +1 -1
  72. package/dist/commands/telemetry/enable.js.map +1 -1
  73. package/dist/commands/telemetry/status.js.map +1 -1
  74. package/dist/context-warnings.d.ts +5 -0
  75. package/dist/context-warnings.js +31 -0
  76. package/dist/context-warnings.js.map +1 -0
  77. package/dist/context-warnings.test.js +28 -0
  78. package/dist/context-warnings.test.js.map +1 -0
  79. package/dist/server/app.d.ts +220 -0
  80. package/dist/server/app.js +295 -0
  81. package/dist/server/app.js.map +1 -0
  82. package/dist/server/app.test.d.ts +1 -0
  83. package/dist/server/app.test.js +97 -0
  84. package/dist/server/app.test.js.map +1 -0
  85. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  86. package/dist/server/asset-base-url-transform-plugin.js +17 -2
  87. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  88. package/dist/server/asset-base-url-transform-plugin.test.js +80 -1
  89. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  90. package/dist/server/auth/discovery.d.ts +33 -0
  91. package/dist/server/auth/discovery.js +56 -0
  92. package/dist/server/auth/discovery.js.map +1 -0
  93. package/dist/server/auth/discovery.test.d.ts +1 -0
  94. package/dist/server/auth/discovery.test.js +93 -0
  95. package/dist/server/auth/discovery.test.js.map +1 -0
  96. package/dist/server/auth/index.d.ts +48 -0
  97. package/dist/server/auth/index.js +2 -0
  98. package/dist/server/auth/index.js.map +1 -0
  99. package/dist/server/auth/providers/auth0.d.ts +40 -0
  100. package/dist/server/auth/providers/auth0.js +36 -0
  101. package/dist/server/auth/providers/auth0.js.map +1 -0
  102. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  103. package/dist/server/auth/providers/auth0.test.js +50 -0
  104. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  105. package/dist/server/auth/providers/authplane.d.ts +49 -0
  106. package/dist/server/auth/providers/authplane.js +57 -0
  107. package/dist/server/auth/providers/authplane.js.map +1 -0
  108. package/dist/server/auth/providers/authplane.test.d.ts +1 -0
  109. package/dist/server/auth/providers/authplane.test.js +143 -0
  110. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  111. package/dist/server/auth/providers/clerk.d.ts +51 -0
  112. package/dist/server/auth/providers/clerk.js +19 -0
  113. package/dist/server/auth/providers/clerk.js.map +1 -0
  114. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  115. package/dist/server/auth/providers/clerk.test.js +30 -0
  116. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  117. package/dist/server/auth/providers/custom.d.ts +42 -0
  118. package/dist/server/auth/providers/custom.js +59 -0
  119. package/dist/server/auth/providers/custom.js.map +1 -0
  120. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  121. package/dist/server/auth/providers/custom.test.js +161 -0
  122. package/dist/server/auth/providers/custom.test.js.map +1 -0
  123. package/dist/server/auth/providers/descope.d.ts +44 -0
  124. package/dist/server/auth/providers/descope.js +44 -0
  125. package/dist/server/auth/providers/descope.js.map +1 -0
  126. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  127. package/dist/server/auth/providers/descope.test.js +62 -0
  128. package/dist/server/auth/providers/descope.test.js.map +1 -0
  129. package/dist/server/auth/providers/shared.d.ts +2 -0
  130. package/dist/server/auth/providers/shared.js +6 -0
  131. package/dist/server/auth/providers/shared.js.map +1 -0
  132. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  133. package/dist/server/auth/providers/shared.test.js +10 -0
  134. package/dist/server/auth/providers/shared.test.js.map +1 -0
  135. package/dist/server/auth/providers/stytch.d.ts +25 -0
  136. package/dist/server/auth/providers/stytch.js +16 -0
  137. package/dist/server/auth/providers/stytch.js.map +1 -0
  138. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  139. package/dist/server/auth/providers/verify-spy.js +21 -0
  140. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  141. package/dist/server/auth/providers/workos.d.ts +34 -0
  142. package/dist/server/auth/providers/workos.js +16 -0
  143. package/dist/server/auth/providers/workos.js.map +1 -0
  144. package/dist/server/auth/security-schemes.d.ts +23 -0
  145. package/dist/server/auth/security-schemes.js +64 -0
  146. package/dist/server/auth/security-schemes.js.map +1 -0
  147. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  148. package/dist/server/auth/security-schemes.test.js +99 -0
  149. package/dist/server/auth/security-schemes.test.js.map +1 -0
  150. package/dist/server/auth/setup.d.ts +6 -0
  151. package/dist/server/auth/setup.js +91 -0
  152. package/dist/server/auth/setup.js.map +1 -0
  153. package/dist/server/auth/setup.test.d.ts +1 -0
  154. package/dist/server/auth/setup.test.js +514 -0
  155. package/dist/server/auth/setup.test.js.map +1 -0
  156. package/dist/server/auth/verify.d.ts +48 -0
  157. package/dist/server/auth/verify.js +62 -0
  158. package/dist/server/auth/verify.js.map +1 -0
  159. package/dist/server/auth/verify.test.d.ts +1 -0
  160. package/dist/server/auth/verify.test.js +165 -0
  161. package/dist/server/auth/verify.test.js.map +1 -0
  162. package/dist/server/auth-extra.test-d.d.ts +1 -0
  163. package/dist/server/auth-extra.test-d.js +130 -0
  164. package/dist/server/auth-extra.test-d.js.map +1 -0
  165. package/dist/server/auth.d.ts +57 -0
  166. package/dist/server/auth.js +27 -0
  167. package/dist/server/auth.js.map +1 -0
  168. package/dist/server/build-manifest.test.d.ts +1 -0
  169. package/dist/server/build-manifest.test.js +28 -0
  170. package/dist/server/build-manifest.test.js.map +1 -0
  171. package/dist/server/content-helpers.d.ts +67 -0
  172. package/dist/server/content-helpers.js +79 -0
  173. package/dist/server/content-helpers.js.map +1 -0
  174. package/dist/server/content-helpers.test.d.ts +1 -0
  175. package/dist/server/content-helpers.test.js +70 -0
  176. package/dist/server/content-helpers.test.js.map +1 -0
  177. package/dist/server/events.d.ts +125 -0
  178. package/dist/server/events.js +449 -0
  179. package/dist/server/events.js.map +1 -0
  180. package/dist/server/events.test.d.ts +1 -0
  181. package/dist/server/events.test.js +142 -0
  182. package/dist/server/events.test.js.map +1 -0
  183. package/dist/server/express.d.ts +23 -7
  184. package/dist/server/express.js +62 -32
  185. package/dist/server/express.js.map +1 -1
  186. package/dist/server/express.test.js +429 -73
  187. package/dist/server/express.test.js.map +1 -1
  188. package/dist/server/file-ref.d.ts +28 -0
  189. package/dist/server/file-ref.js +27 -0
  190. package/dist/server/file-ref.js.map +1 -0
  191. package/dist/server/host.d.ts +2 -0
  192. package/dist/server/host.js +11 -0
  193. package/dist/server/host.js.map +1 -0
  194. package/dist/server/host.test.d.ts +1 -0
  195. package/dist/server/host.test.js +13 -0
  196. package/dist/server/host.test.js.map +1 -0
  197. package/dist/server/index.d.ts +21 -3
  198. package/dist/server/index.js +17 -2
  199. package/dist/server/index.js.map +1 -1
  200. package/dist/server/inferUtilityTypes.d.ts +6 -6
  201. package/dist/server/inferUtilityTypes.js.map +1 -1
  202. package/dist/server/mcp-errors.test.d.ts +1 -0
  203. package/dist/server/mcp-errors.test.js +41 -0
  204. package/dist/server/mcp-errors.test.js.map +1 -0
  205. package/dist/server/metric.d.ts +14 -0
  206. package/dist/server/metric.js +62 -0
  207. package/dist/server/metric.js.map +1 -0
  208. package/dist/server/middleware.d.ts +51 -13
  209. package/dist/server/middleware.js +33 -0
  210. package/dist/server/middleware.js.map +1 -1
  211. package/dist/server/middleware.test-d.js +1 -1
  212. package/dist/server/middleware.test-d.js.map +1 -1
  213. package/dist/server/middleware.test.js +242 -131
  214. package/dist/server/middleware.test.js.map +1 -1
  215. package/dist/server/register-tool.test.d.ts +1 -0
  216. package/dist/server/register-tool.test.js +110 -0
  217. package/dist/server/register-tool.test.js.map +1 -0
  218. package/dist/server/requestOrigin.d.ts +7 -0
  219. package/dist/server/requestOrigin.js +25 -0
  220. package/dist/server/requestOrigin.js.map +1 -0
  221. package/dist/server/server.d.ts +507 -88
  222. package/dist/server/server.js +604 -230
  223. package/dist/server/server.js.map +1 -1
  224. package/dist/server/skills-integration.test.d.ts +1 -0
  225. package/dist/server/skills-integration.test.js +86 -0
  226. package/dist/server/skills-integration.test.js.map +1 -0
  227. package/dist/server/skills.d.ts +27 -0
  228. package/dist/server/skills.js +188 -0
  229. package/dist/server/skills.js.map +1 -0
  230. package/dist/server/skills.test.d.ts +1 -0
  231. package/dist/server/skills.test.js +243 -0
  232. package/dist/server/skills.test.js.map +1 -0
  233. package/dist/server/templateHelper.d.ts +2 -7
  234. package/dist/server/templateHelper.js +3 -22
  235. package/dist/server/templateHelper.js.map +1 -1
  236. package/dist/server/templates.generated.d.ts +4 -0
  237. package/dist/server/templates.generated.js +43 -0
  238. package/dist/server/templates.generated.js.map +1 -0
  239. package/dist/server/tool-extra.test.d.ts +1 -0
  240. package/dist/server/tool-extra.test.js +88 -0
  241. package/dist/server/tool-extra.test.js.map +1 -0
  242. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  243. package/dist/server/tunnel-proxy-router.js +110 -0
  244. package/dist/server/tunnel-proxy-router.js.map +1 -0
  245. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  246. package/dist/server/tunnel-proxy-router.test.js +229 -0
  247. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  248. package/dist/server/view-name.test-d.d.ts +1 -0
  249. package/dist/server/view-name.test-d.js +8 -0
  250. package/dist/server/view-name.test-d.js.map +1 -0
  251. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  252. package/dist/server/view-resource-resolution.test.js +176 -0
  253. package/dist/server/view-resource-resolution.test.js.map +1 -0
  254. package/dist/server/viewsDevServer.d.ts +14 -0
  255. package/dist/server/viewsDevServer.js +48 -0
  256. package/dist/server/viewsDevServer.js.map +1 -0
  257. package/dist/test/utils.d.ts +21 -31
  258. package/dist/test/utils.js +222 -198
  259. package/dist/test/utils.js.map +1 -1
  260. package/dist/test/view.test.d.ts +1 -0
  261. package/dist/test/view.test.js +540 -0
  262. package/dist/test/view.test.js.map +1 -0
  263. package/dist/version.d.ts +1 -0
  264. package/dist/version.js +3 -0
  265. package/dist/version.js.map +1 -0
  266. package/dist/views/index.d.ts +10 -0
  267. package/dist/views/index.js +3 -0
  268. package/dist/views/index.js.map +1 -0
  269. package/dist/views/scan-views.d.ts +16 -0
  270. package/dist/views/scan-views.js +88 -0
  271. package/dist/views/scan-views.js.map +1 -0
  272. package/dist/views/scan-views.test.d.ts +1 -0
  273. package/dist/views/scan-views.test.js +99 -0
  274. package/dist/views/scan-views.test.js.map +1 -0
  275. package/dist/views/validate-view.d.ts +1 -0
  276. package/dist/views/validate-view.js +9 -0
  277. package/dist/views/validate-view.js.map +1 -0
  278. package/dist/views/validate-view.test.d.ts +1 -0
  279. package/dist/views/validate-view.test.js +24 -0
  280. package/dist/views/validate-view.test.js.map +1 -0
  281. package/dist/web/bridges/adaptor.d.ts +56 -0
  282. package/dist/web/bridges/adaptor.js +397 -0
  283. package/dist/web/bridges/adaptor.js.map +1 -0
  284. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  285. package/dist/web/bridges/adaptor.test.js +264 -0
  286. package/dist/web/bridges/adaptor.test.js.map +1 -0
  287. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -1
  288. package/dist/web/bridges/apps-sdk/bridge.js +15 -3
  289. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  290. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  291. package/dist/web/bridges/apps-sdk/index.js +0 -1
  292. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  293. package/dist/web/bridges/apps-sdk/types.d.ts +18 -6
  294. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  295. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  296. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  297. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  298. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  299. package/dist/web/bridges/get-adaptor.js +9 -7
  300. package/dist/web/bridges/get-adaptor.js.map +1 -1
  301. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  302. package/dist/web/bridges/get-adaptor.test.js +32 -0
  303. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  304. package/dist/web/bridges/index.js.map +1 -1
  305. package/dist/web/bridges/mcp-app/bridge.d.ts +15 -2
  306. package/dist/web/bridges/mcp-app/bridge.js +80 -7
  307. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  308. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  309. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  310. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  311. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  312. package/dist/web/bridges/mcp-app/index.js +0 -1
  313. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  314. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  315. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  316. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +13 -1
  317. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  318. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  319. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  320. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  321. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  322. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  323. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  324. package/dist/web/bridges/types.d.ts +154 -12
  325. package/dist/web/bridges/types.js +14 -1
  326. package/dist/web/bridges/types.js.map +1 -1
  327. package/dist/web/bridges/types.test.d.ts +1 -0
  328. package/dist/web/bridges/types.test.js +19 -0
  329. package/dist/web/bridges/types.test.js.map +1 -0
  330. package/dist/web/bridges/use-host-context.d.ts +5 -0
  331. package/dist/web/bridges/use-host-context.js +5 -0
  332. package/dist/web/bridges/use-host-context.js.map +1 -1
  333. package/dist/web/components/modal-provider.d.ts +1 -1
  334. package/dist/web/components/modal-provider.js +4 -3
  335. package/dist/web/components/modal-provider.js.map +1 -1
  336. package/dist/web/create-store.d.ts +26 -0
  337. package/dist/web/create-store.js +43 -3
  338. package/dist/web/create-store.js.map +1 -1
  339. package/dist/web/create-store.test.js +24 -23
  340. package/dist/web/create-store.test.js.map +1 -1
  341. package/dist/web/data-llm.d.ts +35 -2
  342. package/dist/web/data-llm.js +34 -5
  343. package/dist/web/data-llm.js.map +1 -1
  344. package/dist/web/data-llm.test.js +48 -29
  345. package/dist/web/data-llm.test.js.map +1 -1
  346. package/dist/web/generate-helpers.d.ts +40 -32
  347. package/dist/web/generate-helpers.js +38 -30
  348. package/dist/web/generate-helpers.js.map +1 -1
  349. package/dist/web/generate-helpers.test-d.js +33 -31
  350. package/dist/web/generate-helpers.test-d.js.map +1 -1
  351. package/dist/web/generate-helpers.test.js +2 -2
  352. package/dist/web/generate-helpers.test.js.map +1 -1
  353. package/dist/web/helpers/state.d.ts +2 -2
  354. package/dist/web/helpers/state.js +11 -11
  355. package/dist/web/helpers/state.js.map +1 -1
  356. package/dist/web/helpers/state.test.js +9 -9
  357. package/dist/web/helpers/state.test.js.map +1 -1
  358. package/dist/web/hooks/index.d.ts +10 -2
  359. package/dist/web/hooks/index.js +10 -2
  360. package/dist/web/hooks/index.js.map +1 -1
  361. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  362. package/dist/web/hooks/openai-extensions.test.js +107 -0
  363. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  364. package/dist/web/hooks/test/utils.d.ts +7 -2
  365. package/dist/web/hooks/test/utils.js +14 -3
  366. package/dist/web/hooks/test/utils.js.map +1 -1
  367. package/dist/web/hooks/use-call-tool.d.ts +47 -2
  368. package/dist/web/hooks/use-call-tool.js +43 -10
  369. package/dist/web/hooks/use-call-tool.js.map +1 -1
  370. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  371. package/dist/web/hooks/use-call-tool.test.js +75 -29
  372. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  373. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  374. package/dist/web/hooks/use-deep-link.js +34 -0
  375. package/dist/web/hooks/use-deep-link.js.map +1 -0
  376. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  377. package/dist/web/hooks/use-display-mode.js +20 -0
  378. package/dist/web/hooks/use-display-mode.js.map +1 -1
  379. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  380. package/dist/web/hooks/use-display-mode.test.js +57 -21
  381. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  382. package/dist/web/hooks/use-download.d.ts +3 -0
  383. package/dist/web/hooks/use-download.js +7 -0
  384. package/dist/web/hooks/use-download.js.map +1 -0
  385. package/dist/web/hooks/use-download.test.d.ts +1 -0
  386. package/dist/web/hooks/use-download.test.js +103 -0
  387. package/dist/web/hooks/use-download.test.js.map +1 -0
  388. package/dist/web/hooks/use-files.d.ts +34 -1
  389. package/dist/web/hooks/use-files.js +33 -0
  390. package/dist/web/hooks/use-files.js.map +1 -1
  391. package/dist/web/hooks/use-files.test.js +31 -3
  392. package/dist/web/hooks/use-files.test.js.map +1 -1
  393. package/dist/web/hooks/use-host.d.ts +44 -0
  394. package/dist/web/hooks/use-host.js +45 -0
  395. package/dist/web/hooks/use-host.js.map +1 -0
  396. package/dist/web/hooks/use-host.test.d.ts +1 -0
  397. package/dist/web/hooks/use-host.test.js +59 -0
  398. package/dist/web/hooks/use-host.test.js.map +1 -0
  399. package/dist/web/hooks/use-model-context.d.ts +44 -0
  400. package/dist/web/hooks/use-model-context.js +63 -0
  401. package/dist/web/hooks/use-model-context.js.map +1 -0
  402. package/dist/web/hooks/use-open-external.d.ts +17 -0
  403. package/dist/web/hooks/use-open-external.js +16 -0
  404. package/dist/web/hooks/use-open-external.js.map +1 -1
  405. package/dist/web/hooks/use-open-external.test.js +15 -5
  406. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  407. package/dist/web/hooks/use-open-file.d.ts +20 -0
  408. package/dist/web/hooks/use-open-file.js +25 -0
  409. package/dist/web/hooks/use-open-file.js.map +1 -0
  410. package/dist/web/hooks/use-register-view-tool.d.ts +37 -0
  411. package/dist/web/hooks/use-register-view-tool.js +50 -0
  412. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  413. package/dist/web/hooks/use-request-close.d.ts +16 -0
  414. package/dist/web/hooks/use-request-close.js +21 -0
  415. package/dist/web/hooks/use-request-close.js.map +1 -0
  416. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  417. package/dist/web/hooks/use-request-close.test.js +47 -0
  418. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  419. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  420. package/dist/web/hooks/use-request-modal.js +19 -4
  421. package/dist/web/hooks/use-request-modal.js.map +1 -1
  422. package/dist/web/hooks/use-request-modal.test.js +12 -2
  423. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  424. package/dist/web/hooks/use-request-size.d.ts +20 -0
  425. package/dist/web/hooks/use-request-size.js +24 -0
  426. package/dist/web/hooks/use-request-size.js.map +1 -0
  427. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  428. package/dist/web/hooks/use-request-size.test.js +47 -0
  429. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  430. package/dist/web/hooks/use-send-follow-up-message.d.ts +25 -1
  431. package/dist/web/hooks/use-send-follow-up-message.js +25 -2
  432. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  433. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  434. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  435. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  436. package/dist/web/hooks/use-set-open-in-app-url.test.js +26 -12
  437. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  438. package/dist/web/hooks/use-tool-info.d.ts +46 -14
  439. package/dist/web/hooks/use-tool-info.js +29 -7
  440. package/dist/web/hooks/use-tool-info.js.map +1 -1
  441. package/dist/web/hooks/use-tool-info.test-d.js +11 -34
  442. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  443. package/dist/web/hooks/use-tool-info.test.js +42 -37
  444. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  445. package/dist/web/hooks/use-user.d.ts +5 -2
  446. package/dist/web/hooks/use-user.js +6 -3
  447. package/dist/web/hooks/use-user.js.map +1 -1
  448. package/dist/web/hooks/use-user.test.js +85 -37
  449. package/dist/web/hooks/use-user.test.js.map +1 -1
  450. package/dist/web/hooks/use-view-state.d.ts +25 -0
  451. package/dist/web/hooks/use-view-state.js +42 -0
  452. package/dist/web/hooks/use-view-state.js.map +1 -0
  453. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  454. package/dist/web/hooks/use-view-state.test.js +212 -0
  455. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  456. package/dist/web/hooks/use-viewport.d.ts +20 -0
  457. package/dist/web/hooks/use-viewport.js +21 -0
  458. package/dist/web/hooks/use-viewport.js.map +1 -0
  459. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  460. package/dist/web/hooks/use-viewport.test.js +109 -0
  461. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  462. package/dist/web/index.d.ts +1 -2
  463. package/dist/web/index.js +1 -2
  464. package/dist/web/index.js.map +1 -1
  465. package/dist/web/mount-view.d.ts +21 -0
  466. package/dist/web/mount-view.js +43 -0
  467. package/dist/web/mount-view.js.map +1 -0
  468. package/dist/web/proxy.js.map +1 -1
  469. package/dist/web/types.d.ts +4 -0
  470. package/dist/web/types.js.map +1 -1
  471. package/package.json +47 -27
  472. package/tsconfig.base.json +2 -0
  473. package/dist/server/templates/development.hbs +0 -12
  474. package/dist/server/templates/production.hbs +0 -6
  475. package/dist/server/widgetsDevServer.d.ts +0 -13
  476. package/dist/server/widgetsDevServer.js +0 -52
  477. package/dist/server/widgetsDevServer.js.map +0 -1
  478. package/dist/test/widget.test.js +0 -263
  479. package/dist/test/widget.test.js.map +0 -1
  480. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -22
  481. package/dist/web/bridges/apps-sdk/adaptor.js +0 -75
  482. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  483. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -38
  484. package/dist/web/bridges/mcp-app/adaptor.js +0 -184
  485. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  486. package/dist/web/hooks/use-layout.d.ts +0 -22
  487. package/dist/web/hooks/use-layout.js +0 -23
  488. package/dist/web/hooks/use-layout.js.map +0 -1
  489. package/dist/web/hooks/use-layout.test.js +0 -96
  490. package/dist/web/hooks/use-layout.test.js.map +0 -1
  491. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  492. package/dist/web/hooks/use-widget-state.js +0 -32
  493. package/dist/web/hooks/use-widget-state.js.map +0 -1
  494. package/dist/web/hooks/use-widget-state.test.js +0 -64
  495. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  496. package/dist/web/mount-widget.d.ts +0 -1
  497. package/dist/web/mount-widget.js +0 -27
  498. package/dist/web/mount-widget.js.map +0 -1
  499. package/dist/web/plugin/data-llm.test.js +0 -81
  500. package/dist/web/plugin/data-llm.test.js.map +0 -1
  501. package/dist/web/plugin/plugin.d.ts +0 -2
  502. package/dist/web/plugin/plugin.js +0 -54
  503. package/dist/web/plugin/plugin.js.map +0 -1
  504. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  505. package/dist/web/plugin/transform-data-llm.js +0 -96
  506. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  507. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  508. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  509. package/dist/web/plugin/validate-widget.d.ts +0 -5
  510. package/dist/web/plugin/validate-widget.js +0 -27
  511. package/dist/web/plugin/validate-widget.js.map +0 -1
  512. package/dist/web/plugin/validate-widget.test.js +0 -42
  513. package/dist/web/plugin/validate-widget.test.js.map +0 -1
  514. /package/dist/{test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  515. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  516. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  517. /package/dist/{web/plugin/data-llm.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  518. /package/dist/{web/plugin/transform-data-llm.test.d.ts → cli/tunnel.test.d.ts} +0 -0
  519. /package/dist/{web/plugin/validate-widget.test.d.ts → context-warnings.test.d.ts} +0 -0
@@ -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 { OAuthConfig, OAuthProvider } from \"./auth/index.js\";\nimport { type ResourceMetadataUrlResolver, setupOAuth } from \"./auth/setup.js\";\nimport type { ExtraClaims } from \"./auth.js\";\nimport {\n type EmittedEvent,\n type EventDef,\n type EventsOptions,\n EventsRuntime,\n} from \"./events.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 type JsonOptions,\n McpServer,\n type McpServerTypes,\n type ToolDef,\n} from \"./server.js\";\n\nconst SLOW_HANDLER_THRESHOLD_MS = 50;\n\ntype ErrorMiddlewareConfig = {\n path?: string;\n handlers: ErrorRequestHandler[];\n};\n\n/**\n * The `handler` field of {@link SkybridgeConfig}: builds the app's MCP\n * surface. Runs again for **every incoming request**, on a fresh\n * {@link McpServer}, so keep it to registration: pools, clients and any other\n * one-time work belong in `setup`, whose result is the second argument. It\n * must **return** the chained server so `typeof app` carries the registered\n * tool types.\n *\n * @typeParam TConfig - What `setup` resolved to, passed as the second argument.\n */\nexport type SkybridgeHandler<\n TTools extends Record<string, ToolDef>,\n TConfig,\n TAuthExtra extends ExtraClaims,\n TEvents extends Record<string, EventDef> = Record<never, EventDef>,\n> = (\n server: McpServer<Record<never, ToolDef>, TAuthExtra>,\n config: TConfig,\n) => McpServer<TTools, TAuthExtra, TEvents>;\n\n/**\n * What the `oauth` field accepts: an {@link OAuthConfig}, a provider\n * (`oauth: auth0Provider(...)`), or a function of the `setup` result returning\n * either. Providers and functions resolve once, at {@link Skybridge.run} or on\n * the first request, never at module import. Anything asynchronous belongs in\n * a provider's `resolve`.\n */\nexport type SkybridgeOAuthInput<TConfig, TExtra extends ExtraClaims> =\n | OAuthConfig<TExtra>\n | OAuthProvider<TExtra>\n | ((config: TConfig) => OAuthConfig<TExtra> | OAuthProvider<TExtra>);\n\nasync function resolveOAuthInput<TConfig, TExtra extends ExtraClaims>(\n input: SkybridgeOAuthInput<TConfig, TExtra> | undefined,\n config: TConfig,\n): Promise<OAuthConfig<TExtra> | undefined> {\n const resolved = typeof input === \"function\" ? input(config) : input;\n return resolved && \"resolve\" in resolved\n ? await resolved.resolve()\n : resolved;\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`, …), the Express and skills options, and the app's behavior\n * (`setup`, `oauth`, `handler`).\n *\n * All type parameters are inferred from the value: the config from `setup`,\n * the auth claims from `oauth`, and the tool registry from the server\n * `handler` returns.\n */\nexport type SkybridgeConfig<\n TTools extends Record<string, ToolDef> = Record<never, ToolDef>,\n TConfig = undefined,\n TAuthExtra extends ExtraClaims = ExtraClaims,\n TEvents extends Record<string, EventDef> = Record<never, EventDef>,\n> = Implementation &\n ServerOptions & {\n /** Options for the built-in `express.json()` middleware, e.g. `{ limit: \"10mb\" }`. */\n json?: JsonOptions;\n /**\n * @experimental Serve Agent Skills from `src/skills` over MCP (SEP-2640).\n * API may change.\n */\n skills?: boolean;\n /**\n * @experimental MCP Events options: where webhook subscriptions are kept.\n * Only used when the handler registers events. API may change.\n */\n events?: EventsOptions;\n /**\n * Loads whatever the app needs up front (remote config, secrets, datasets,\n * …). Runs **once** — at {@link Skybridge.run} or on the first request,\n * never at module import — and its awaited return value is passed to an\n * `oauth` function and to `handler` as the second argument.\n */\n setup?: () => TConfig;\n /**\n * Resource-server OAuth. When set, mounts the well-known metadata routes\n * and bearer auth on `/mcp`, and the verifier's claims type\n * `extra.http.authInfo.extra` in tool handlers.\n */\n oauth?: SkybridgeOAuthInput<Awaited<TConfig>, TAuthExtra>;\n /** Registers the MCP surface, per request. See {@link SkybridgeHandler}. */\n handler: SkybridgeHandler<TTools, Awaited<TConfig>, TAuthExtra, TEvents>;\n };\n\n/**\n * A Skybridge app: the HTTP surface (Express, OAuth metadata, the `/mcp`\n * route) plus a handler that builds the MCP server for each request.\n *\n * The handler 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 handler body other than registration therefore runs per request too.\n * Anything asynchronous the app needs (remote config, secrets, …) goes in\n * `setup`, which runs once and feeds the handler's second argument.\n *\n * @example\n * ```ts\n * export const app = new Skybridge({\n * name: \"my-app\",\n * version: \"1.0.0\",\n * setup: async () => loadConfig(),\n * oauth: (config) => descopeProvider({ url: config.mcpServerUrl }),\n * handler: (server, config) =>\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 TConfig = undefined,\n TAuthExtra extends ExtraClaims = ExtraClaims,\n TEvents extends Record<string, EventDef> = Record<never, EventDef>,\n> {\n declare readonly $types: McpServerTypes<TTools>;\n private readonly eventsRuntime: EventsRuntime;\n private readonly serverInfo: Implementation;\n private readonly serverOptions: ServerOptions;\n private readonly skills?: boolean;\n private oauthEnabled = false;\n private readonly handler: SkybridgeHandler<\n TTools,\n Awaited<TConfig>,\n TAuthExtra,\n TEvents\n >;\n private readonly setup?: () => TConfig;\n private readonly oauthInput?: SkybridgeOAuthInput<\n Awaited<TConfig>,\n TAuthExtra\n >;\n private config?: Awaited<TConfig>;\n private readonly expressApp: Express;\n private readonly errorMiddleware: ErrorMiddlewareConfig[] = [];\n private readonly monitoringEntry: McpMiddlewareEntry | null =\n createMiddlewareEntry();\n private resolveResourceMetadataUrl?: ResourceMetadataUrlResolver;\n private readyPromise?: Promise<void>;\n private slowHandlerWarned = false;\n\n constructor({\n name,\n title,\n version,\n description,\n icons,\n websiteUrl,\n json,\n skills,\n events,\n setup,\n oauth,\n handler,\n ...serverOptions\n }: SkybridgeConfig<TTools, TConfig, TAuthExtra, TEvents>) {\n this.serverInfo = { name, title, version, description, icons, websiteUrl };\n this.serverOptions = serverOptions;\n this.skills = skills;\n this.eventsRuntime = new EventsRuntime(events);\n this.setup = setup;\n this.oauthInput = oauth;\n this.handler = handler;\n this.expressApp = createBaseApp(json);\n }\n\n /**\n * Resolve `setup` and `oauth`, then wire OAuth onto the Express app. Runs\n * once; every entry point that needs a built server awaits it, and a failed\n * attempt is retried on the next call.\n *\n * @internal\n */\n ready(): Promise<void> {\n this.readyPromise ??= (async () => {\n if (this.setup) {\n this.config = await this.setup();\n }\n const oauth = await resolveOAuthInput(\n this.oauthInput,\n this.config as Awaited<TConfig>,\n );\n this.oauthEnabled = Boolean(oauth);\n const sample = this.buildServer();\n if (oauth) {\n this.resolveResourceMetadataUrl = setupOAuth(\n this.expressApp,\n oauth,\n sample.securitySchemesByTool,\n );\n }\n })().catch((error) => {\n this.readyPromise = undefined;\n throw error;\n });\n return this.readyPromise;\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\" }, handler })`.\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 handler 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 `setup` and the `oauth` input on first use.\n */\n async createServerInstance(): Promise<SdkServer> {\n await this.ready();\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 * @experimental Deliver an occurrence of an event registered with\n * `registerEvent` to every live subscription its `match` hook accepts. The\n * payload is validated against the event's `payloadSchema`. Resolves once\n * each delivery got a first attempt; failed deliveries are retried in the\n * background. Rejects with an `AggregateError` when `match` hooks throw,\n * after the other deliveries went out. API may change.\n *\n * @example\n * ```ts\n * await app.emit(\"comment.created\", {\n * id: comment.id,\n * data: { documentId: comment.docId, excerpt: comment.text.slice(0, 280) },\n * });\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/register-event\n */\n async emit<TName extends keyof TEvents & string>(\n name: TName,\n event: EmittedEvent<TEvents[TName][\"payload\"]>,\n ): Promise<void> {\n await this.ready();\n await this.eventsRuntime.emit(name, event);\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 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, TEvents> {\n const server = new McpServer<Record<never, ToolDef>, TAuthExtra>(\n this.serverInfo,\n this.serverOptions,\n {\n skills: this.skills,\n oauth: this.oauthEnabled,\n events: this.eventsRuntime,\n },\n );\n if (this.resolveResourceMetadataUrl) {\n server.setResourceMetadataUrlResolver(this.resolveResourceMetadataUrl);\n }\n const startedAt = performance.now();\n const built = this.handler(server, this.config as Awaited<TConfig>);\n const elapsed = performance.now() - startedAt;\n if (typeof (built as { then?: unknown }).then === \"function\") {\n throw new Error(\n \"The Skybridge handler must be synchronous — it runs on every request. Load config or secrets in `setup` instead and read them from the handler's second argument.\",\n );\n }\n if (elapsed > SLOW_HANDLER_THRESHOLD_MS && !this.slowHandlerWarned) {\n this.slowHandlerWarned = true;\n console.warn(\n `The Skybridge handler took ${Math.round(elapsed)}ms — it runs on every request, so this cost is paid per request. Move expensive work into \\`setup\\`, whose result is passed to the handler.`,\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"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,97 @@
1
+ import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
2
+ import { describe, expect, it } from "vitest";
3
+ import { Skybridge } from "./app.js";
4
+ const oauthConfig = {
5
+ oauthMetadata: {
6
+ issuer: "https://issuer.example.com",
7
+ authorization_endpoint: "https://issuer.example.com/authorize",
8
+ token_endpoint: "https://issuer.example.com/token",
9
+ response_types_supported: ["code"],
10
+ },
11
+ verifier: {
12
+ verifyAccessToken: async () => ({
13
+ token: "t",
14
+ clientId: "c",
15
+ scopes: [],
16
+ extra: {},
17
+ }),
18
+ },
19
+ };
20
+ describe("Skybridge setup and handler", () => {
21
+ it("resolves setup once and passes the context to the per-request handler", async () => {
22
+ let loads = 0;
23
+ const app = new Skybridge({
24
+ name: "test",
25
+ version: "1.0.0",
26
+ setup: async () => {
27
+ loads++;
28
+ return { greeting: await Promise.resolve("hello") };
29
+ },
30
+ handler: (server, { greeting }) => server.registerTool({ name: "greet", description: "greet" }, async () => ({ content: [{ type: "text", text: greeting }] })),
31
+ });
32
+ expect(loads).toBe(0);
33
+ const call = async () => {
34
+ const client = new Client({ name: "client", version: "1.0.0" });
35
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
36
+ await app.connect(serverTransport);
37
+ await client.connect(clientTransport);
38
+ const result = await client.callTool({ name: "greet" });
39
+ await client.close();
40
+ return result;
41
+ };
42
+ expect(await call()).toMatchObject({
43
+ content: [{ type: "text", text: "hello" }],
44
+ });
45
+ expect(await call()).toMatchObject({
46
+ content: [{ type: "text", text: "hello" }],
47
+ });
48
+ expect(loads).toBe(1);
49
+ });
50
+ it("retries setup after a failed first resolution", async () => {
51
+ let attempts = 0;
52
+ const app = new Skybridge({
53
+ name: "test",
54
+ version: "1.0.0",
55
+ setup: async () => {
56
+ attempts++;
57
+ if (attempts === 1) {
58
+ throw new Error("transient");
59
+ }
60
+ },
61
+ handler: (server) => server,
62
+ });
63
+ const [, first] = InMemoryTransport.createLinkedPair();
64
+ await expect(app.connect(first)).rejects.toThrow("transient");
65
+ const [, second] = InMemoryTransport.createLinkedPair();
66
+ await expect(app.connect(second)).resolves.toBeUndefined();
67
+ expect(attempts).toBe(2);
68
+ });
69
+ it("rejects a handler that returns a promise", async () => {
70
+ const app = new Skybridge({
71
+ name: "test",
72
+ version: "1.0.0",
73
+ // @ts-expect-error the handler runs per request and must stay synchronous
74
+ handler: async (server) => server,
75
+ });
76
+ const [, serverTransport] = InMemoryTransport.createLinkedPair();
77
+ await expect(app.connect(serverTransport)).rejects.toThrow(/must be synchronous/);
78
+ });
79
+ it("resolves an oauth function with the setup config before wiring the routes", async () => {
80
+ let seen;
81
+ const app = new Skybridge({
82
+ name: "test",
83
+ version: "1.0.0",
84
+ setup: () => ({ issuer: "https://issuer.example.com" }),
85
+ oauth: (config) => {
86
+ seen = config;
87
+ return oauthConfig;
88
+ },
89
+ handler: (server) => server,
90
+ });
91
+ expect(seen).toBeUndefined();
92
+ const [, serverTransport] = InMemoryTransport.createLinkedPair();
93
+ await app.connect(serverTransport);
94
+ expect(seen).toEqual({ issuer: "https://issuer.example.com" });
95
+ });
96
+ });
97
+ //# sourceMappingURL=app.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.test.js","sourceRoot":"","sources":["../../src/server/app.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Client, InMemoryTransport } from \"@modelcontextprotocol/client\";\nimport { describe, expect, it } from \"vitest\";\nimport { Skybridge } from \"./app.js\";\n\nconst oauthConfig = {\n oauthMetadata: {\n issuer: \"https://issuer.example.com\",\n authorization_endpoint: \"https://issuer.example.com/authorize\",\n token_endpoint: \"https://issuer.example.com/token\",\n response_types_supported: [\"code\"],\n },\n verifier: {\n verifyAccessToken: async () => ({\n token: \"t\",\n clientId: \"c\",\n scopes: [],\n extra: {},\n }),\n },\n};\n\ndescribe(\"Skybridge setup and handler\", () => {\n it(\"resolves setup once and passes the context to the per-request handler\", async () => {\n let loads = 0;\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n setup: async () => {\n loads++;\n return { greeting: await Promise.resolve(\"hello\") };\n },\n handler: (server, { greeting }) =>\n server.registerTool(\n { name: \"greet\", description: \"greet\" },\n async () => ({ content: [{ type: \"text\", text: greeting }] }),\n ),\n });\n\n expect(loads).toBe(0);\n\n const call = async () => {\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await app.connect(serverTransport);\n await client.connect(clientTransport);\n const result = await client.callTool({ name: \"greet\" });\n await client.close();\n return result;\n };\n\n expect(await call()).toMatchObject({\n content: [{ type: \"text\", text: \"hello\" }],\n });\n expect(await call()).toMatchObject({\n content: [{ type: \"text\", text: \"hello\" }],\n });\n expect(loads).toBe(1);\n });\n\n it(\"retries setup after a failed first resolution\", async () => {\n let attempts = 0;\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n setup: async () => {\n attempts++;\n if (attempts === 1) {\n throw new Error(\"transient\");\n }\n },\n handler: (server) => server,\n });\n\n const [, first] = InMemoryTransport.createLinkedPair();\n await expect(app.connect(first)).rejects.toThrow(\"transient\");\n\n const [, second] = InMemoryTransport.createLinkedPair();\n await expect(app.connect(second)).resolves.toBeUndefined();\n expect(attempts).toBe(2);\n });\n\n it(\"rejects a handler that returns a promise\", async () => {\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n // @ts-expect-error the handler runs per request and must stay synchronous\n handler: async (server) => server,\n });\n const [, serverTransport] = InMemoryTransport.createLinkedPair();\n await expect(app.connect(serverTransport)).rejects.toThrow(\n /must be synchronous/,\n );\n });\n\n it(\"resolves an oauth function with the setup config before wiring the routes\", async () => {\n let seen: unknown;\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n setup: () => ({ issuer: \"https://issuer.example.com\" }),\n oauth: (config) => {\n seen = config;\n return oauthConfig;\n },\n handler: (server) => server,\n });\n\n expect(seen).toBeUndefined();\n const [, serverTransport] = InMemoryTransport.createLinkedPair();\n await app.connect(serverTransport);\n expect(seen).toEqual({ issuer: \"https://issuer.example.com\" });\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"]}
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { assetBaseUrlTransform } from "./asset-base-url-transform-plugin.js";
2
+ import { assetBaseUrlTransform, assetBaseUrlTransformPlugin, isCssRequest, } from "./asset-base-url-transform-plugin.js";
3
3
  describe("assetBaseUrlTransform", () => {
4
4
  it("should transform asset paths to use window.skybridge.serverUrl", () => {
5
5
  const cases = [
@@ -51,5 +51,84 @@ describe("assetBaseUrlTransform", () => {
51
51
  const result = assetBaseUrlTransform(code);
52
52
  expect(result).toBe(code);
53
53
  });
54
+ it("should not transform asset paths inside static `import ... from` clauses", () => {
55
+ // Reproducer for #713: a dep does `import * as sprite from './icons.svg'`,
56
+ // Vite resolves the relative path to absolute, then this transform used
57
+ // to rewrite the resolved string — producing invalid JS like
58
+ // `import * as sprite from (expr) + "..."` that crashes vite:import-analysis.
59
+ const cases = [
60
+ `import * as sprite from "/Users/me/proj/node_modules/pkg/icons.svg";`,
61
+ `import sprite from '/assets/icons.svg';`,
62
+ `import sprite from "/assets/icons.svg";`,
63
+ `export { default } from "/assets/icons.svg";`,
64
+ `export * from '/assets/sprites.svg';`,
65
+ ];
66
+ for (const code of cases) {
67
+ expect(assetBaseUrlTransform(code)).toBe(code);
68
+ }
69
+ });
70
+ it("should still transform value-position asset paths in files that also have unrelated imports", () => {
71
+ const code = [
72
+ `import { foo } from "./foo.js";`,
73
+ `import * as sprite from "/assets/sprite.svg";`,
74
+ `const logo = "/assets/logo.png";`,
75
+ ].join("\n");
76
+ const result = assetBaseUrlTransform(code);
77
+ // Imports untouched
78
+ expect(result).toContain(`from "./foo.js"`);
79
+ expect(result).toContain(`from "/assets/sprite.svg"`);
80
+ // Value-position rewritten
81
+ expect(result).toContain(`const logo = (window.skybridge?.serverUrl ?? "") + "/assets/logo.png";`);
82
+ });
83
+ });
84
+ describe("isCssRequest", () => {
85
+ it("returns true for CSS-family extensions", () => {
86
+ expect(isCssRequest("/src/styles.css")).toBe(true);
87
+ expect(isCssRequest("/src/styles.module.css")).toBe(true);
88
+ expect(isCssRequest("/src/styles.scss")).toBe(true);
89
+ expect(isCssRequest("/src/styles.sass")).toBe(true);
90
+ expect(isCssRequest("/src/styles.less")).toBe(true);
91
+ expect(isCssRequest("/src/styles.styl")).toBe(true);
92
+ });
93
+ it("returns true for CSS modules with Vite query strings", () => {
94
+ expect(isCssRequest("/src/styles.css?direct")).toBe(true);
95
+ expect(isCssRequest("/src/styles.css?inline")).toBe(true);
96
+ expect(isCssRequest("/src/styles.css?used")).toBe(true);
97
+ expect(isCssRequest("/src/Foo.vue?vue&type=style&lang.css")).toBe(true);
98
+ });
99
+ it("returns false for non-CSS modules", () => {
100
+ expect(isCssRequest("/src/index.tsx")).toBe(false);
101
+ expect(isCssRequest("/src/utils.ts")).toBe(false);
102
+ expect(isCssRequest("/src/Logo.svg")).toBe(false);
103
+ expect(isCssRequest("/src/notes.cssx")).toBe(false);
104
+ });
105
+ });
106
+ describe("assetBaseUrlTransformPlugin", () => {
107
+ function runTransform(id, code) {
108
+ const plugin = assetBaseUrlTransformPlugin();
109
+ const hook = plugin.transform;
110
+ if (!hook) {
111
+ throw new Error("plugin.transform is not defined");
112
+ }
113
+ const handler = typeof hook === "function" ? hook : hook.handler;
114
+ return handler.call(
115
+ // biome-ignore lint/suspicious/noExplicitAny: vitest harness for plugin hook
116
+ {}, code, id, { moduleType: "js" });
117
+ }
118
+ it("rewrites asset paths in JS modules", () => {
119
+ const result = runTransform("/src/widget.tsx", `const logo = "/assets/logo.png";`);
120
+ expect(result?.code).toContain(`(window.skybridge?.serverUrl ?? "") + "/assets/logo.png"`);
121
+ });
122
+ // Reproducer for #697: CSS imports are served as JS modules with the
123
+ // stylesheet embedded as a string. Rewriting url("/foo.woff2") inside that
124
+ // string would produce invalid CSS once the styles are injected.
125
+ it("does not rewrite asset paths when transforming a CSS module", () => {
126
+ const cssCode = `__vite__updateStyle("style-id", "@font-face { src: url(\\"/fonts/Brand.woff2\\") format(\\"woff2\\"); }");`;
127
+ expect(runTransform("/src/fonts.css", cssCode)).toBeNull();
128
+ expect(runTransform("/src/fonts.css?direct", cssCode)).toBeNull();
129
+ expect(runTransform("/src/fonts.css?inline", cssCode)).toBeNull();
130
+ expect(runTransform("/src/styles.scss", cssCode)).toBeNull();
131
+ expect(runTransform("/src/Foo.vue?vue&type=style&lang.css", cssCode)).toBeNull();
132
+ });
54
133
  });
55
134
  //# sourceMappingURL=asset-base-url-transform-plugin.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset-base-url-transform-plugin.test.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,KAAK,GAAG;YACZ;gBACE,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,mCAAmC;gBACzC,QAAQ,EAAE,yEAAyE;aACpF;YACD;gBACE,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,mCAAmC;gBACzC,QAAQ,EAAE,yEAAyE;aACpF;YACD;gBACE,IAAI,EAAE,iBAAiB;gBACvB,IAAI,EAAE,mCAAmC;gBACzC,QAAQ,EAAE,yEAAyE;aACpF;SACF,CAAC;QAEF,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,IAAI,GAAG;;;;KAIZ,CAAC;QACF,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,0DAA0D,CAC3D,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,0DAA0D,CAC3D,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,4DAA4D,CAC7D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG;;;;KAIZ,CAAC;QACF,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,0DAA0D,CAC3D,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,IAAI,GAAG,6BAA6B,CAAC;QAC3C,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"asset-base-url-transform-plugin.test.js","sourceRoot":"","sources":["../../src/server/asset-base-url-transform-plugin.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport {\n assetBaseUrlTransform,\n assetBaseUrlTransformPlugin,\n isCssRequest,\n} from \"./asset-base-url-transform-plugin.js\";\n\ndescribe(\"assetBaseUrlTransform\", () => {\n it(\"should transform asset paths to use window.skybridge.serverUrl\", () => {\n const cases = [\n {\n desc: \"single-quoted\",\n code: `const image = '/assets/logo.png';`,\n expected: `const image = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n },\n {\n desc: \"double-quoted\",\n code: `const image = \"/assets/logo.png\";`,\n expected: `const image = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n },\n {\n desc: \"backtick-quoted\",\n code: \"const image = `/assets/logo.png`;\",\n expected: `const image = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n },\n ];\n\n for (const { code, expected } of cases) {\n const result = assetBaseUrlTransform(code);\n expect(result).toBe(expected);\n }\n });\n\n it(\"should transform multiple asset paths\", () => {\n const code = `\n const logo = '/assets/logo.png';\n const icon = '/assets/icon.svg';\n const font = '/assets/font.woff2';\n `;\n const result = assetBaseUrlTransform(code);\n\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\"`,\n );\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/icon.svg\"`,\n );\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/font.woff2\"`,\n );\n });\n\n it(\"should not transform already absolute URLs\", () => {\n const code = `\n const local = '/assets/logo.png';\n const http = 'http://example.com/image.png';\n const https = 'https://example.com/image.png';\n `;\n const result = assetBaseUrlTransform(code);\n\n expect(result).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\"`,\n );\n expect(result).toContain(\"http://example.com/image.png\");\n expect(result).toContain(\"https://example.com/image.png\");\n });\n\n it(\"should not transform code without asset paths\", () => {\n const code = `const text = \"Hello World\";`;\n const result = assetBaseUrlTransform(code);\n\n expect(result).toBe(code);\n });\n\n it(\"should not transform asset paths inside static `import ... from` clauses\", () => {\n // Reproducer for #713: a dep does `import * as sprite from './icons.svg'`,\n // Vite resolves the relative path to absolute, then this transform used\n // to rewrite the resolved string — producing invalid JS like\n // `import * as sprite from (expr) + \"...\"` that crashes vite:import-analysis.\n const cases = [\n `import * as sprite from \"/Users/me/proj/node_modules/pkg/icons.svg\";`,\n `import sprite from '/assets/icons.svg';`,\n `import sprite from \"/assets/icons.svg\";`,\n `export { default } from \"/assets/icons.svg\";`,\n `export * from '/assets/sprites.svg';`,\n ];\n\n for (const code of cases) {\n expect(assetBaseUrlTransform(code)).toBe(code);\n }\n });\n\n it(\"should still transform value-position asset paths in files that also have unrelated imports\", () => {\n const code = [\n `import { foo } from \"./foo.js\";`,\n `import * as sprite from \"/assets/sprite.svg\";`,\n `const logo = \"/assets/logo.png\";`,\n ].join(\"\\n\");\n const result = assetBaseUrlTransform(code);\n\n // Imports untouched\n expect(result).toContain(`from \"./foo.js\"`);\n expect(result).toContain(`from \"/assets/sprite.svg\"`);\n // Value-position rewritten\n expect(result).toContain(\n `const logo = (window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\";`,\n );\n });\n});\n\ndescribe(\"isCssRequest\", () => {\n it(\"returns true for CSS-family extensions\", () => {\n expect(isCssRequest(\"/src/styles.css\")).toBe(true);\n expect(isCssRequest(\"/src/styles.module.css\")).toBe(true);\n expect(isCssRequest(\"/src/styles.scss\")).toBe(true);\n expect(isCssRequest(\"/src/styles.sass\")).toBe(true);\n expect(isCssRequest(\"/src/styles.less\")).toBe(true);\n expect(isCssRequest(\"/src/styles.styl\")).toBe(true);\n });\n\n it(\"returns true for CSS modules with Vite query strings\", () => {\n expect(isCssRequest(\"/src/styles.css?direct\")).toBe(true);\n expect(isCssRequest(\"/src/styles.css?inline\")).toBe(true);\n expect(isCssRequest(\"/src/styles.css?used\")).toBe(true);\n expect(isCssRequest(\"/src/Foo.vue?vue&type=style&lang.css\")).toBe(true);\n });\n\n it(\"returns false for non-CSS modules\", () => {\n expect(isCssRequest(\"/src/index.tsx\")).toBe(false);\n expect(isCssRequest(\"/src/utils.ts\")).toBe(false);\n expect(isCssRequest(\"/src/Logo.svg\")).toBe(false);\n expect(isCssRequest(\"/src/notes.cssx\")).toBe(false);\n });\n});\n\ndescribe(\"assetBaseUrlTransformPlugin\", () => {\n type TransformResult = { code: string; map: null } | null;\n\n function runTransform(id: string, code: string): TransformResult {\n const plugin = assetBaseUrlTransformPlugin();\n const hook = plugin.transform;\n if (!hook) {\n throw new Error(\"plugin.transform is not defined\");\n }\n const handler = typeof hook === \"function\" ? hook : hook.handler;\n return handler.call(\n // biome-ignore lint/suspicious/noExplicitAny: vitest harness for plugin hook\n {} as any,\n code,\n id,\n { moduleType: \"js\" },\n ) as TransformResult;\n }\n\n it(\"rewrites asset paths in JS modules\", () => {\n const result = runTransform(\n \"/src/widget.tsx\",\n `const logo = \"/assets/logo.png\";`,\n );\n expect(result?.code).toContain(\n `(window.skybridge?.serverUrl ?? \"\") + \"/assets/logo.png\"`,\n );\n });\n\n // Reproducer for #697: CSS imports are served as JS modules with the\n // stylesheet embedded as a string. Rewriting url(\"/foo.woff2\") inside that\n // string would produce invalid CSS once the styles are injected.\n it(\"does not rewrite asset paths when transforming a CSS module\", () => {\n const cssCode = `__vite__updateStyle(\"style-id\", \"@font-face { src: url(\\\\\"/fonts/Brand.woff2\\\\\") format(\\\\\"woff2\\\\\"); }\");`;\n\n expect(runTransform(\"/src/fonts.css\", cssCode)).toBeNull();\n expect(runTransform(\"/src/fonts.css?direct\", cssCode)).toBeNull();\n expect(runTransform(\"/src/fonts.css?inline\", cssCode)).toBeNull();\n expect(runTransform(\"/src/styles.scss\", cssCode)).toBeNull();\n expect(\n runTransform(\"/src/Foo.vue?vue&type=style&lang.css\", cssCode),\n ).toBeNull();\n });\n});\n"]}
@@ -0,0 +1,33 @@
1
+ import { z } from "zod/v4";
2
+ /**
3
+ * Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's
4
+ * `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but
5
+ * we need it for JWKS token verification, so we extend the schema to keep it.
6
+ */
7
+ declare const DiscoverySchema: z.ZodObject<{
8
+ issuer: z.ZodString;
9
+ authorization_endpoint: z.ZodURL;
10
+ token_endpoint: z.ZodURL;
11
+ registration_endpoint: z.ZodOptional<z.ZodURL>;
12
+ scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
13
+ response_types_supported: z.ZodArray<z.ZodString>;
14
+ response_modes_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
15
+ grant_types_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
16
+ token_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
17
+ token_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
18
+ service_documentation: z.ZodOptional<z.ZodURL>;
19
+ revocation_endpoint: z.ZodOptional<z.ZodURL>;
20
+ revocation_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
21
+ revocation_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
22
+ introspection_endpoint: z.ZodOptional<z.ZodString>;
23
+ introspection_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
24
+ introspection_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
25
+ code_challenge_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
26
+ client_id_metadata_document_supported: z.ZodOptional<z.ZodBoolean>;
27
+ authorization_response_iss_parameter_supported: z.ZodCatch<z.ZodOptional<z.ZodBoolean>>;
28
+ jwks_uri: z.ZodOptional<z.ZodString>;
29
+ }, z.core.$loose>;
30
+ export type DiscoveredMetadata = z.infer<typeof DiscoverySchema>;
31
+ /** Fetches and validates an authorization server's discovery document. */
32
+ export declare function discoverAuthorizationServer(issuer: string): Promise<DiscoveredMetadata>;
33
+ export {};
@@ -0,0 +1,56 @@
1
+ import { OAuthMetadataSchema } from "@modelcontextprotocol/core";
2
+ import { z } from "zod/v4";
3
+ /**
4
+ * Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's
5
+ * `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but
6
+ * we need it for JWKS token verification, so we extend the schema to keep it.
7
+ */
8
+ const DiscoverySchema = OAuthMetadataSchema.extend({
9
+ jwks_uri: z.string().optional(),
10
+ });
11
+ const WELL_KNOWN = [
12
+ "/.well-known/openid-configuration",
13
+ "/.well-known/oauth-authorization-server",
14
+ ];
15
+ const DISCOVERY_TIMEOUT_MS = 5000;
16
+ /** Fetches and validates an authorization server's discovery document. */
17
+ export async function discoverAuthorizationServer(issuer) {
18
+ const base = issuer.replace(/\/$/, "");
19
+ const errors = [];
20
+ // First valid doc lacking a registration_endpoint, kept as a fallback so a
21
+ // genuinely non-DCR IdP still resolves (and is rejected later by the caller).
22
+ let fallback;
23
+ for (const path of WELL_KNOWN) {
24
+ const url = `${base}${path}`;
25
+ // Any failure (network/timeout, non-2xx, non-JSON, invalid metadata, issuer
26
+ // mismatch) records a per-URL reason and falls through to the next path.
27
+ try {
28
+ const res = await fetch(url, {
29
+ signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS),
30
+ });
31
+ if (!res.ok) {
32
+ throw new Error(`HTTP ${res.status}`);
33
+ }
34
+ const meta = DiscoverySchema.parse(await res.json());
35
+ // RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).
36
+ if (meta.issuer.replace(/\/$/, "") !== base) {
37
+ throw new Error(`issuer mismatch: ${meta.issuer}`);
38
+ }
39
+ // Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a
40
+ // valid openid-configuration without `registration_endpoint` yet expose
41
+ // it at oauth-authorization-server. Keep looking past a doc that omits it.
42
+ if (meta.registration_endpoint) {
43
+ return meta;
44
+ }
45
+ fallback ??= meta;
46
+ }
47
+ catch (err) {
48
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
49
+ }
50
+ }
51
+ if (fallback) {
52
+ return fallback;
53
+ }
54
+ throw new Error(`OAuth discovery failed for ${issuer}: ${errors.join("; ")}`);
55
+ }
56
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B;;;;GAIG;AACH,MAAM,eAAe,GAAG,mBAAmB,CAAC,MAAM,CAAC;IACjD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAGH,MAAM,UAAU,GAAG;IACjB,mCAAmC;IACnC,yCAAyC;CAC1C,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,QAAwC,CAAC;IAE7C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,yEAAyE;QACzE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC3B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC;aAClD,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACxC,CAAC;YACD,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACrD,yEAAyE;YACzE,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5C,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACrD,CAAC;YACD,0EAA0E;YAC1E,wEAAwE;YACxE,2EAA2E;YAC3E,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC;YACd,CAAC;YACD,QAAQ,KAAK,IAAI,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CACT,GAAG,GAAG,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC","sourcesContent":["import { OAuthMetadataSchema } from \"@modelcontextprotocol/core\";\nimport { z } from \"zod/v4\";\n\n/**\n * Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's\n * `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but\n * we need it for JWKS token verification, so we extend the schema to keep it.\n */\nconst DiscoverySchema = OAuthMetadataSchema.extend({\n jwks_uri: z.string().optional(),\n});\nexport type DiscoveredMetadata = z.infer<typeof DiscoverySchema>;\n\nconst WELL_KNOWN = [\n \"/.well-known/openid-configuration\",\n \"/.well-known/oauth-authorization-server\",\n];\n\nconst DISCOVERY_TIMEOUT_MS = 5000;\n\n/** Fetches and validates an authorization server's discovery document. */\nexport async function discoverAuthorizationServer(\n issuer: string,\n): Promise<DiscoveredMetadata> {\n const base = issuer.replace(/\\/$/, \"\");\n const errors: string[] = [];\n // First valid doc lacking a registration_endpoint, kept as a fallback so a\n // genuinely non-DCR IdP still resolves (and is rejected later by the caller).\n let fallback: DiscoveredMetadata | undefined;\n\n for (const path of WELL_KNOWN) {\n const url = `${base}${path}`;\n // Any failure (network/timeout, non-2xx, non-JSON, invalid metadata, issuer\n // mismatch) records a per-URL reason and falls through to the next path.\n try {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS),\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n const meta = DiscoverySchema.parse(await res.json());\n // RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).\n if (meta.issuer.replace(/\\/$/, \"\") !== base) {\n throw new Error(`issuer mismatch: ${meta.issuer}`);\n }\n // Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a\n // valid openid-configuration without `registration_endpoint` yet expose\n // it at oauth-authorization-server. Keep looking past a doc that omits it.\n if (meta.registration_endpoint) {\n return meta;\n }\n fallback ??= meta;\n } catch (err) {\n errors.push(\n `${url}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (fallback) {\n return fallback;\n }\n throw new Error(`OAuth discovery failed for ${issuer}: ${errors.join(\"; \")}`);\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,93 @@
1
+ // @vitest-environment node
2
+ import http from "node:http";
3
+ import { afterEach, describe, expect, it } from "vitest";
4
+ import { discoverAuthorizationServer } from "./discovery.js";
5
+ let server;
6
+ afterEach(() => server?.close());
7
+ function doc(origin, extra = {}) {
8
+ return {
9
+ issuer: origin,
10
+ authorization_endpoint: `${origin}/authorize`,
11
+ token_endpoint: `${origin}/token`,
12
+ registration_endpoint: `${origin}/register`,
13
+ response_types_supported: ["code"],
14
+ scopes_supported: ["openid", "email"],
15
+ jwks_uri: `${origin}/jwks`,
16
+ ...extra,
17
+ };
18
+ }
19
+ // Serves JSON bodies built from the live origin at their well-known paths;
20
+ // returns the origin URL.
21
+ async function serve(build) {
22
+ let origin = "";
23
+ const srv = http.createServer((req, res) => {
24
+ const body = build(origin)[req.url ?? ""];
25
+ if (body === undefined) {
26
+ res.writeHead(404).end();
27
+ return;
28
+ }
29
+ res.setHeader("content-type", "application/json");
30
+ res.end(JSON.stringify(body));
31
+ });
32
+ await new Promise((resolve) => srv.listen(0, resolve));
33
+ server = srv;
34
+ origin = `http://localhost:${srv.address().port}`;
35
+ return origin;
36
+ }
37
+ describe("discoverAuthorizationServer", () => {
38
+ it("fetches and validates openid-configuration", async () => {
39
+ const base = await serve((o) => ({
40
+ "/.well-known/openid-configuration": doc(o),
41
+ }));
42
+ const meta = await discoverAuthorizationServer(base);
43
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
44
+ expect(meta.jwks_uri).toBe(`${base}/jwks`);
45
+ });
46
+ it("accepts a canonically slash-terminated issuer", async () => {
47
+ const base = await serve((o) => ({
48
+ "/.well-known/openid-configuration": doc(o, { issuer: `${o}/` }),
49
+ }));
50
+ const meta = await discoverAuthorizationServer(base);
51
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
52
+ });
53
+ it("falls back to oauth-authorization-server when oidc is 404", async () => {
54
+ const base = await serve((o) => ({
55
+ "/.well-known/oauth-authorization-server": doc(o),
56
+ }));
57
+ const meta = await discoverAuthorizationServer(base);
58
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
59
+ });
60
+ it("throws when no well-known doc is reachable", async () => {
61
+ const base = await serve(() => ({}));
62
+ await expect(discoverAuthorizationServer(base)).rejects.toThrow(/discovery failed/i);
63
+ });
64
+ it("falls through to oauth-authorization-server when oidc doc is schema-invalid", async () => {
65
+ const base = await serve((o) => ({
66
+ "/.well-known/openid-configuration": doc(o, {
67
+ response_types_supported: undefined,
68
+ }),
69
+ "/.well-known/oauth-authorization-server": doc(o),
70
+ }));
71
+ const meta = await discoverAuthorizationServer(base);
72
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
73
+ });
74
+ it("prefers the doc advertising DCR when oidc omits registration_endpoint", async () => {
75
+ // Clerk-shaped: valid openid-configuration without a registration_endpoint,
76
+ // DCR exposed only at oauth-authorization-server.
77
+ const base = await serve((o) => ({
78
+ "/.well-known/openid-configuration": doc(o, {
79
+ registration_endpoint: undefined,
80
+ }),
81
+ "/.well-known/oauth-authorization-server": doc(o),
82
+ }));
83
+ const meta = await discoverAuthorizationServer(base);
84
+ expect(meta.registration_endpoint).toBe(`${base}/register`);
85
+ });
86
+ it("rejects a doc whose issuer does not match the fetch origin", async () => {
87
+ const base = await serve(() => ({
88
+ "/.well-known/openid-configuration": doc("https://evil.test"),
89
+ }));
90
+ await expect(discoverAuthorizationServer(base)).rejects.toThrow(/discovery failed/i);
91
+ });
92
+ });
93
+ //# sourceMappingURL=discovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\nimport http from \"node:http\";\nimport { afterEach, describe, expect, it } from \"vitest\";\nimport { discoverAuthorizationServer } from \"./discovery.js\";\n\nlet server: http.Server | undefined;\nafterEach(() => server?.close());\n\nfunction doc(origin: string, extra: Record<string, unknown> = {}) {\n return {\n issuer: origin,\n authorization_endpoint: `${origin}/authorize`,\n token_endpoint: `${origin}/token`,\n registration_endpoint: `${origin}/register`,\n response_types_supported: [\"code\"],\n scopes_supported: [\"openid\", \"email\"],\n jwks_uri: `${origin}/jwks`,\n ...extra,\n };\n}\n\n// Serves JSON bodies built from the live origin at their well-known paths;\n// returns the origin URL.\nasync function serve(build: (origin: string) => Record<string, unknown>) {\n let origin = \"\";\n const srv = http.createServer((req, res) => {\n const body = build(origin)[req.url ?? \"\"];\n if (body === undefined) {\n res.writeHead(404).end();\n return;\n }\n res.setHeader(\"content-type\", \"application/json\");\n res.end(JSON.stringify(body));\n });\n await new Promise<void>((resolve) => srv.listen(0, resolve));\n server = srv;\n origin = `http://localhost:${(srv.address() as { port: number }).port}`;\n return origin;\n}\n\ndescribe(\"discoverAuthorizationServer\", () => {\n it(\"fetches and validates openid-configuration\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n expect(meta.jwks_uri).toBe(`${base}/jwks`);\n });\n\n it(\"accepts a canonically slash-terminated issuer\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, { issuer: `${o}/` }),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"falls back to oauth-authorization-server when oidc is 404\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"throws when no well-known doc is reachable\", async () => {\n const base = await serve(() => ({}));\n await expect(discoverAuthorizationServer(base)).rejects.toThrow(\n /discovery failed/i,\n );\n });\n\n it(\"falls through to oauth-authorization-server when oidc doc is schema-invalid\", async () => {\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, {\n response_types_supported: undefined,\n }),\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"prefers the doc advertising DCR when oidc omits registration_endpoint\", async () => {\n // Clerk-shaped: valid openid-configuration without a registration_endpoint,\n // DCR exposed only at oauth-authorization-server.\n const base = await serve((o) => ({\n \"/.well-known/openid-configuration\": doc(o, {\n registration_endpoint: undefined,\n }),\n \"/.well-known/oauth-authorization-server\": doc(o),\n }));\n const meta = await discoverAuthorizationServer(base);\n expect(meta.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"rejects a doc whose issuer does not match the fetch origin\", async () => {\n const base = await serve(() => ({\n \"/.well-known/openid-configuration\": doc(\"https://evil.test\"),\n }));\n await expect(discoverAuthorizationServer(base)).rejects.toThrow(\n /discovery failed/i,\n );\n });\n});\n"]}