skybridge 0.0.0-dev.ac7f0da → 0.0.0-dev.ac96bba

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 (429) hide show
  1. package/README.md +124 -115
  2. package/dist/cli/build-helpers.d.ts +10 -0
  3. package/dist/cli/build-helpers.js +93 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +89 -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 +68 -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 +18 -0
  13. package/dist/cli/detect-port.js +50 -0
  14. package/dist/cli/detect-port.js.map +1 -0
  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-views-dir.d.ts +1 -0
  19. package/dist/cli/resolve-views-dir.js +17 -0
  20. package/dist/cli/resolve-views-dir.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 +89 -0
  24. package/dist/cli/run-plain.js.map +1 -0
  25. package/dist/cli/telemetry.js.map +1 -1
  26. package/dist/cli/tunnel-control-server.d.ts +9 -0
  27. package/dist/cli/tunnel-control-server.js +31 -0
  28. package/dist/cli/tunnel-control-server.js.map +1 -0
  29. package/dist/cli/tunnel-control-server.test.d.ts +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.d.ts +1 -0
  36. package/dist/cli/tunnel-handler.test.js +105 -0
  37. package/dist/cli/tunnel-handler.test.js.map +1 -0
  38. package/dist/cli/tunnel.d.ts +57 -0
  39. package/dist/cli/tunnel.js +154 -0
  40. package/dist/cli/tunnel.js.map +1 -0
  41. package/dist/cli/tunnel.test.d.ts +1 -0
  42. package/dist/cli/tunnel.test.js +190 -0
  43. package/dist/cli/tunnel.test.js.map +1 -0
  44. package/dist/cli/types.d.ts +5 -0
  45. package/dist/cli/types.js +2 -0
  46. package/dist/cli/types.js.map +1 -0
  47. package/dist/cli/use-execute-steps.d.ts +1 -1
  48. package/dist/cli/use-execute-steps.js.map +1 -1
  49. package/dist/cli/use-messages.d.ts +3 -0
  50. package/dist/cli/use-messages.js +11 -0
  51. package/dist/cli/use-messages.js.map +1 -0
  52. package/dist/cli/use-nodemon.d.ts +16 -6
  53. package/dist/cli/use-nodemon.js +77 -54
  54. package/dist/cli/use-nodemon.js.map +1 -1
  55. package/dist/cli/use-open-browser.d.ts +1 -0
  56. package/dist/cli/use-open-browser.js +44 -0
  57. package/dist/cli/use-open-browser.js.map +1 -0
  58. package/dist/cli/use-tunnel.d.ts +14 -0
  59. package/dist/cli/use-tunnel.js +131 -0
  60. package/dist/cli/use-tunnel.js.map +1 -0
  61. package/dist/cli/use-typescript-check.d.ts +9 -2
  62. package/dist/cli/use-typescript-check.js +89 -51
  63. package/dist/cli/use-typescript-check.js.map +1 -1
  64. package/dist/commands/build.d.ts +0 -3
  65. package/dist/commands/build.js +3 -18
  66. package/dist/commands/build.js.map +1 -1
  67. package/dist/commands/create.d.ts +9 -0
  68. package/dist/commands/create.js +30 -0
  69. package/dist/commands/create.js.map +1 -0
  70. package/dist/commands/dev.d.ts +5 -1
  71. package/dist/commands/dev.js +105 -8
  72. package/dist/commands/dev.js.map +1 -1
  73. package/dist/commands/start.d.ts +3 -1
  74. package/dist/commands/start.js +37 -15
  75. package/dist/commands/start.js.map +1 -1
  76. package/dist/commands/telemetry/disable.js.map +1 -1
  77. package/dist/commands/telemetry/enable.js.map +1 -1
  78. package/dist/commands/telemetry/status.js.map +1 -1
  79. package/dist/server/asset-base-url-transform-plugin.d.ts +6 -6
  80. package/dist/server/asset-base-url-transform-plugin.js +25 -11
  81. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  82. package/dist/server/asset-base-url-transform-plugin.test.js +92 -14
  83. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  84. package/dist/server/auth/discovery.d.ts +40 -0
  85. package/dist/server/auth/discovery.js +81 -0
  86. package/dist/server/auth/discovery.js.map +1 -0
  87. package/dist/server/auth/discovery.test.d.ts +1 -0
  88. package/dist/server/auth/discovery.test.js +105 -0
  89. package/dist/server/auth/discovery.test.js.map +1 -0
  90. package/dist/server/auth/index.d.ts +18 -0
  91. package/dist/server/auth/index.js +2 -0
  92. package/dist/server/auth/index.js.map +1 -0
  93. package/dist/server/auth/providers/auth0.d.ts +18 -0
  94. package/dist/server/auth/providers/auth0.js +31 -0
  95. package/dist/server/auth/providers/auth0.js.map +1 -0
  96. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  97. package/dist/server/auth/providers/auth0.test.js +48 -0
  98. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  99. package/dist/server/auth/providers/clerk.d.ts +14 -0
  100. package/dist/server/auth/providers/clerk.js +16 -0
  101. package/dist/server/auth/providers/clerk.js.map +1 -0
  102. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  103. package/dist/server/auth/providers/clerk.test.js +28 -0
  104. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  105. package/dist/server/auth/providers/custom.d.ts +24 -0
  106. package/dist/server/auth/providers/custom.js +37 -0
  107. package/dist/server/auth/providers/custom.js.map +1 -0
  108. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  109. package/dist/server/auth/providers/custom.test.js +107 -0
  110. package/dist/server/auth/providers/custom.test.js.map +1 -0
  111. package/dist/server/auth/providers/descope.d.ts +15 -0
  112. package/dist/server/auth/providers/descope.js +52 -0
  113. package/dist/server/auth/providers/descope.js.map +1 -0
  114. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  115. package/dist/server/auth/providers/descope.test.js +61 -0
  116. package/dist/server/auth/providers/descope.test.js.map +1 -0
  117. package/dist/server/auth/providers/shared.d.ts +2 -0
  118. package/dist/server/auth/providers/shared.js +6 -0
  119. package/dist/server/auth/providers/shared.js.map +1 -0
  120. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  121. package/dist/server/auth/providers/shared.test.js +10 -0
  122. package/dist/server/auth/providers/shared.test.js.map +1 -0
  123. package/dist/server/auth/providers/stytch.d.ts +12 -0
  124. package/dist/server/auth/providers/stytch.js +13 -0
  125. package/dist/server/auth/providers/stytch.js.map +1 -0
  126. package/dist/server/auth/providers/workos.d.ts +11 -0
  127. package/dist/server/auth/providers/workos.js +12 -0
  128. package/dist/server/auth/providers/workos.js.map +1 -0
  129. package/dist/server/auth/setup.d.ts +4 -0
  130. package/dist/server/auth/setup.js +51 -0
  131. package/dist/server/auth/setup.js.map +1 -0
  132. package/dist/server/auth/setup.test.d.ts +1 -0
  133. package/dist/server/auth/setup.test.js +185 -0
  134. package/dist/server/auth/setup.test.js.map +1 -0
  135. package/dist/server/auth/verify.d.ts +12 -0
  136. package/dist/server/auth/verify.js +38 -0
  137. package/dist/server/auth/verify.js.map +1 -0
  138. package/dist/server/auth/verify.test.d.ts +1 -0
  139. package/dist/server/auth/verify.test.js +100 -0
  140. package/dist/server/auth/verify.test.js.map +1 -0
  141. package/dist/server/auth.d.ts +20 -0
  142. package/dist/server/auth.js +28 -0
  143. package/dist/server/auth.js.map +1 -0
  144. package/dist/server/build-manifest.test.d.ts +1 -0
  145. package/dist/server/build-manifest.test.js +27 -0
  146. package/dist/server/build-manifest.test.js.map +1 -0
  147. package/dist/server/content-helpers.d.ts +67 -0
  148. package/dist/server/content-helpers.js +79 -0
  149. package/dist/server/content-helpers.js.map +1 -0
  150. package/dist/server/content-helpers.test.d.ts +1 -0
  151. package/dist/server/content-helpers.test.js +70 -0
  152. package/dist/server/content-helpers.test.js.map +1 -0
  153. package/dist/server/express.d.ts +11 -0
  154. package/dist/server/express.js +101 -0
  155. package/dist/server/express.js.map +1 -0
  156. package/dist/server/express.test.d.ts +1 -0
  157. package/dist/server/express.test.js +491 -0
  158. package/dist/server/express.test.js.map +1 -0
  159. package/dist/server/file-ref.d.ts +28 -0
  160. package/dist/server/file-ref.js +27 -0
  161. package/dist/server/file-ref.js.map +1 -0
  162. package/dist/server/index.d.ts +14 -3
  163. package/dist/server/index.js +11 -2
  164. package/dist/server/index.js.map +1 -1
  165. package/dist/server/inferUtilityTypes.d.ts +6 -6
  166. package/dist/server/inferUtilityTypes.js.map +1 -1
  167. package/dist/server/metric.d.ts +14 -0
  168. package/dist/server/metric.js +62 -0
  169. package/dist/server/metric.js.map +1 -0
  170. package/dist/server/middleware.d.ts +137 -0
  171. package/dist/server/middleware.js +93 -0
  172. package/dist/server/middleware.js.map +1 -0
  173. package/dist/server/middleware.test-d.d.ts +1 -0
  174. package/dist/server/middleware.test-d.js +75 -0
  175. package/dist/server/middleware.test-d.js.map +1 -0
  176. package/dist/server/middleware.test.d.ts +1 -0
  177. package/dist/server/middleware.test.js +493 -0
  178. package/dist/server/middleware.test.js.map +1 -0
  179. package/dist/server/requestOrigin.d.ts +7 -0
  180. package/dist/server/requestOrigin.js +25 -0
  181. package/dist/server/requestOrigin.js.map +1 -0
  182. package/dist/server/server.d.ts +379 -59
  183. package/dist/server/server.js +591 -98
  184. package/dist/server/server.js.map +1 -1
  185. package/dist/server/templateHelper.d.ts +5 -7
  186. package/dist/server/templateHelper.js +3 -22
  187. package/dist/server/templateHelper.js.map +1 -1
  188. package/dist/server/templates.generated.d.ts +4 -0
  189. package/dist/server/templates.generated.js +47 -0
  190. package/dist/server/templates.generated.js.map +1 -0
  191. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  192. package/dist/server/tunnel-proxy-router.js +110 -0
  193. package/dist/server/tunnel-proxy-router.js.map +1 -0
  194. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  195. package/dist/server/tunnel-proxy-router.test.js +229 -0
  196. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  197. package/dist/server/view-name.test-d.d.ts +1 -0
  198. package/dist/server/view-name.test-d.js +8 -0
  199. package/dist/server/view-name.test-d.js.map +1 -0
  200. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  201. package/dist/server/view-resource-resolution.test.js +171 -0
  202. package/dist/server/view-resource-resolution.test.js.map +1 -0
  203. package/dist/server/viewsDevServer.d.ts +14 -0
  204. package/dist/server/viewsDevServer.js +45 -0
  205. package/dist/server/viewsDevServer.js.map +1 -0
  206. package/dist/test/utils.d.ts +13 -21
  207. package/dist/test/utils.js +42 -37
  208. package/dist/test/utils.js.map +1 -1
  209. package/dist/test/view.test.d.ts +1 -0
  210. package/dist/test/view.test.js +536 -0
  211. package/dist/test/view.test.js.map +1 -0
  212. package/dist/version.d.ts +1 -0
  213. package/dist/version.js +3 -0
  214. package/dist/version.js.map +1 -0
  215. package/dist/web/bridges/adaptor.d.ts +51 -0
  216. package/dist/web/bridges/adaptor.js +330 -0
  217. package/dist/web/bridges/adaptor.js.map +1 -0
  218. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  219. package/dist/web/bridges/adaptor.test.js +208 -0
  220. package/dist/web/bridges/adaptor.test.js.map +1 -0
  221. package/dist/web/bridges/apps-sdk/bridge.d.ts +7 -2
  222. package/dist/web/bridges/apps-sdk/bridge.js +15 -3
  223. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  224. package/dist/web/bridges/apps-sdk/index.d.ts +1 -2
  225. package/dist/web/bridges/apps-sdk/index.js +0 -1
  226. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  227. package/dist/web/bridges/apps-sdk/types.d.ts +32 -14
  228. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  229. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  230. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  231. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  232. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  233. package/dist/web/bridges/get-adaptor.js +9 -7
  234. package/dist/web/bridges/get-adaptor.js.map +1 -1
  235. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  236. package/dist/web/bridges/get-adaptor.test.js +32 -0
  237. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  238. package/dist/web/bridges/index.js.map +1 -1
  239. package/dist/web/bridges/mcp-app/bridge.d.ts +27 -31
  240. package/dist/web/bridges/mcp-app/bridge.js +109 -198
  241. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  242. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  243. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  244. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  245. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  246. package/dist/web/bridges/mcp-app/index.js +0 -1
  247. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  248. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  249. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +17 -3
  250. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +14 -2
  251. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  252. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -41
  253. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  254. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  255. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  256. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  257. package/dist/web/bridges/types.d.ts +130 -14
  258. package/dist/web/bridges/types.js +14 -1
  259. package/dist/web/bridges/types.js.map +1 -1
  260. package/dist/web/bridges/types.test.d.ts +1 -0
  261. package/dist/web/bridges/types.test.js +19 -0
  262. package/dist/web/bridges/types.test.js.map +1 -0
  263. package/dist/web/bridges/use-host-context.d.ts +5 -0
  264. package/dist/web/bridges/use-host-context.js +5 -0
  265. package/dist/web/bridges/use-host-context.js.map +1 -1
  266. package/dist/web/components/modal-provider.d.ts +1 -1
  267. package/dist/web/components/modal-provider.js +5 -6
  268. package/dist/web/components/modal-provider.js.map +1 -1
  269. package/dist/web/create-store.d.ts +26 -0
  270. package/dist/web/create-store.js +43 -3
  271. package/dist/web/create-store.js.map +1 -1
  272. package/dist/web/create-store.test.js +31 -25
  273. package/dist/web/create-store.test.js.map +1 -1
  274. package/dist/web/data-llm.d.ts +35 -2
  275. package/dist/web/data-llm.js +31 -3
  276. package/dist/web/data-llm.js.map +1 -1
  277. package/dist/web/data-llm.test.js +50 -35
  278. package/dist/web/data-llm.test.js.map +1 -1
  279. package/dist/web/generate-helpers.d.ts +22 -18
  280. package/dist/web/generate-helpers.js +22 -18
  281. package/dist/web/generate-helpers.js.map +1 -1
  282. package/dist/web/generate-helpers.test-d.js +30 -28
  283. package/dist/web/generate-helpers.test-d.js.map +1 -1
  284. package/dist/web/generate-helpers.test.js.map +1 -1
  285. package/dist/web/helpers/state.d.ts +2 -2
  286. package/dist/web/helpers/state.js +11 -11
  287. package/dist/web/helpers/state.js.map +1 -1
  288. package/dist/web/helpers/state.test.js +9 -9
  289. package/dist/web/helpers/state.test.js.map +1 -1
  290. package/dist/web/hooks/index.d.ts +6 -2
  291. package/dist/web/hooks/index.js +5 -1
  292. package/dist/web/hooks/index.js.map +1 -1
  293. package/dist/web/hooks/test/utils.d.ts +6 -2
  294. package/dist/web/hooks/test/utils.js +17 -2
  295. package/dist/web/hooks/test/utils.js.map +1 -1
  296. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  297. package/dist/web/hooks/use-call-tool.js +28 -0
  298. package/dist/web/hooks/use-call-tool.js.map +1 -1
  299. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  300. package/dist/web/hooks/use-call-tool.test.js +62 -27
  301. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  302. package/dist/web/hooks/use-display-mode.d.ts +23 -3
  303. package/dist/web/hooks/use-display-mode.js +20 -0
  304. package/dist/web/hooks/use-display-mode.js.map +1 -1
  305. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  306. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  307. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  308. package/dist/web/hooks/use-display-mode.test.js +56 -20
  309. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  310. package/dist/web/hooks/use-download.d.ts +5 -0
  311. package/dist/web/hooks/use-download.js +8 -0
  312. package/dist/web/hooks/use-download.js.map +1 -0
  313. package/dist/web/hooks/use-download.test.d.ts +1 -0
  314. package/dist/web/hooks/use-download.test.js +103 -0
  315. package/dist/web/hooks/use-download.test.js.map +1 -0
  316. package/dist/web/hooks/use-files.d.ts +34 -1
  317. package/dist/web/hooks/use-files.js +33 -0
  318. package/dist/web/hooks/use-files.js.map +1 -1
  319. package/dist/web/hooks/use-files.test.js +35 -3
  320. package/dist/web/hooks/use-files.test.js.map +1 -1
  321. package/dist/web/hooks/use-layout.d.ts +2 -0
  322. package/dist/web/hooks/use-layout.js +2 -0
  323. package/dist/web/hooks/use-layout.js.map +1 -1
  324. package/dist/web/hooks/use-layout.test.js +62 -29
  325. package/dist/web/hooks/use-layout.test.js.map +1 -1
  326. package/dist/web/hooks/use-open-external.d.ts +20 -1
  327. package/dist/web/hooks/use-open-external.js +17 -1
  328. package/dist/web/hooks/use-open-external.js.map +1 -1
  329. package/dist/web/hooks/use-open-external.test.js +38 -13
  330. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  331. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  332. package/dist/web/hooks/use-register-view-tool.js +50 -0
  333. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  334. package/dist/web/hooks/use-request-close.d.ts +16 -0
  335. package/dist/web/hooks/use-request-close.js +21 -0
  336. package/dist/web/hooks/use-request-close.js.map +1 -0
  337. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  338. package/dist/web/hooks/use-request-close.test.js +47 -0
  339. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  340. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  341. package/dist/web/hooks/use-request-modal.js +19 -4
  342. package/dist/web/hooks/use-request-modal.js.map +1 -1
  343. package/dist/web/hooks/use-request-modal.test.js +15 -1
  344. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  345. package/dist/web/hooks/use-request-size.d.ts +20 -0
  346. package/dist/web/hooks/use-request-size.js +24 -0
  347. package/dist/web/hooks/use-request-size.js.map +1 -0
  348. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  349. package/dist/web/hooks/use-request-size.test.js +47 -0
  350. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  351. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  352. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  353. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  354. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  355. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  356. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  357. package/dist/web/hooks/use-set-open-in-app-url.test.js +30 -16
  358. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  359. package/dist/web/hooks/use-tool-info.d.ts +53 -2
  360. package/dist/web/hooks/use-tool-info.js +30 -7
  361. package/dist/web/hooks/use-tool-info.js.map +1 -1
  362. package/dist/web/hooks/use-tool-info.test-d.js +11 -29
  363. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  364. package/dist/web/hooks/use-tool-info.test.js +43 -33
  365. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  366. package/dist/web/hooks/use-user.d.ts +2 -0
  367. package/dist/web/hooks/use-user.js +20 -2
  368. package/dist/web/hooks/use-user.js.map +1 -1
  369. package/dist/web/hooks/use-user.test.js +101 -27
  370. package/dist/web/hooks/use-user.test.js.map +1 -1
  371. package/dist/web/hooks/use-view-state.d.ts +25 -0
  372. package/dist/web/hooks/use-view-state.js +32 -0
  373. package/dist/web/hooks/use-view-state.js.map +1 -0
  374. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  375. package/dist/web/hooks/use-view-state.test.js +181 -0
  376. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  377. package/dist/web/index.d.ts +1 -2
  378. package/dist/web/index.js +1 -2
  379. package/dist/web/index.js.map +1 -1
  380. package/dist/web/mount-view.d.ts +20 -0
  381. package/dist/web/{mount-widget.js → mount-view.js} +21 -2
  382. package/dist/web/mount-view.js.map +1 -0
  383. package/dist/web/plugin/data-llm.test.js.map +1 -1
  384. package/dist/web/plugin/plugin.d.ts +32 -1
  385. package/dist/web/plugin/plugin.js +160 -18
  386. package/dist/web/plugin/plugin.js.map +1 -1
  387. package/dist/web/plugin/scan-views.d.ts +16 -0
  388. package/dist/web/plugin/scan-views.js +88 -0
  389. package/dist/web/plugin/scan-views.js.map +1 -0
  390. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  391. package/dist/web/plugin/scan-views.test.js +99 -0
  392. package/dist/web/plugin/scan-views.test.js.map +1 -0
  393. package/dist/web/plugin/transform-data-llm.js +1 -1
  394. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  395. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  396. package/dist/web/plugin/validate-view.d.ts +1 -0
  397. package/dist/web/plugin/validate-view.js +9 -0
  398. package/dist/web/plugin/validate-view.js.map +1 -0
  399. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  400. package/dist/web/plugin/validate-view.test.js +24 -0
  401. package/dist/web/plugin/validate-view.test.js.map +1 -0
  402. package/dist/web/proxy.js +0 -1
  403. package/dist/web/proxy.js.map +1 -1
  404. package/dist/web/types.d.ts +4 -0
  405. package/dist/web/types.js.map +1 -1
  406. package/package.json +49 -28
  407. package/tsconfig.base.json +33 -0
  408. package/dist/server/templates/development.hbs +0 -65
  409. package/dist/server/templates/production.hbs +0 -6
  410. package/dist/server/widgetsDevServer.d.ts +0 -12
  411. package/dist/server/widgetsDevServer.js +0 -52
  412. package/dist/server/widgetsDevServer.js.map +0 -1
  413. package/dist/test/widget.test.js +0 -255
  414. package/dist/test/widget.test.js.map +0 -1
  415. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -22
  416. package/dist/web/bridges/apps-sdk/adaptor.js +0 -64
  417. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  418. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -36
  419. package/dist/web/bridges/mcp-app/adaptor.js +0 -185
  420. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  421. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  422. package/dist/web/hooks/use-widget-state.js +0 -32
  423. package/dist/web/hooks/use-widget-state.js.map +0 -1
  424. package/dist/web/hooks/use-widget-state.test.js +0 -61
  425. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  426. package/dist/web/mount-widget.d.ts +0 -1
  427. package/dist/web/mount-widget.js.map +0 -1
  428. /package/dist/{test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  429. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/build-steps.test.d.ts} +0 -0
@@ -0,0 +1,16 @@
1
+ import { customProvider } from "./custom.js";
2
+ import { toIssuerUrl } from "./shared.js";
3
+ /**
4
+ * OAuth provider for Clerk. `domain` is the Frontend API URL (e.g.
5
+ * `acme.clerk.accounts.dev`, or a production custom domain). Requires Dynamic
6
+ * Client Registration enabled on the instance, and the OAuth application set to
7
+ * issue JWT access tokens (opaque tokens can't be JWKS-verified).
8
+ *
9
+ * Clerk access tokens carry no `aud` claim, so there is no `audience` option —
10
+ * verification is issuer + JWKS only (matching Clerk's own `mcpAuthClerk`).
11
+ */
12
+ export function clerkProvider(opts) {
13
+ const { domain, ...rest } = opts;
14
+ return customProvider({ issuer: toIssuerUrl(domain), ...rest });
15
+ }
16
+ //# sourceMappingURL=clerk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clerk.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/clerk.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAC3B,IAA6E;IAE7E,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,cAAc,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import type { OAuthConfig } from \"../index.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\nimport { toIssuerUrl } from \"./shared.js\";\n\n/**\n * OAuth provider for Clerk. `domain` is the Frontend API URL (e.g.\n * `acme.clerk.accounts.dev`, or a production custom domain). Requires Dynamic\n * Client Registration enabled on the instance, and the OAuth application set to\n * issue JWT access tokens (opaque tokens can't be JWKS-verified).\n *\n * Clerk access tokens carry no `aud` claim, so there is no `audience` option —\n * verification is issuer + JWKS only (matching Clerk's own `mcpAuthClerk`).\n */\nexport function clerkProvider(\n opts: { domain: string } & Omit<CustomProviderOptions, \"issuer\" | \"audience\">,\n): Promise<OAuthConfig> {\n const { domain, ...rest } = opts;\n return customProvider({ issuer: toIssuerUrl(domain), ...rest });\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ // @vitest-environment node
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { clerkProvider } from "./clerk.js";
4
+ afterEach(() => vi.restoreAllMocks());
5
+ function doc(issuer) {
6
+ return {
7
+ issuer,
8
+ authorization_endpoint: `${issuer}/oauth/authorize`,
9
+ token_endpoint: `${issuer}/oauth/token`,
10
+ registration_endpoint: `${issuer}/oauth/register`,
11
+ response_types_supported: ["code"],
12
+ scopes_supported: ["profile", "email"],
13
+ jwks_uri: `${issuer}/.well-known/jwks.json`,
14
+ };
15
+ }
16
+ describe("clerkProvider", () => {
17
+ it("verifies issuer + JWKS with no audience (Clerk tokens carry no aud)", async () => {
18
+ const issuer = "https://acme.clerk.accounts.dev";
19
+ const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(JSON.stringify(doc(issuer)), {
20
+ headers: { "content-type": "application/json" },
21
+ }));
22
+ const config = await clerkProvider({ domain: "acme.clerk.accounts.dev" });
23
+ expect(fetchSpy).toHaveBeenCalledWith(`${issuer}/.well-known/openid-configuration`, expect.anything());
24
+ expect(config.verify.issuer).toBe(issuer);
25
+ expect(config.verify.audience).toBeUndefined();
26
+ });
27
+ });
28
+ //# sourceMappingURL=clerk.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clerk.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/clerk.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,SAAS,GAAG,CAAC,MAAc;IACzB,OAAO;QACL,MAAM;QACN,sBAAsB,EAAE,GAAG,MAAM,kBAAkB;QACnD,cAAc,EAAE,GAAG,MAAM,cAAc;QACvC,qBAAqB,EAAE,GAAG,MAAM,iBAAiB;QACjD,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,gBAAgB,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;QACtC,QAAQ,EAAE,GAAG,MAAM,wBAAwB;KAC5C,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,iCAAiC,CAAC;QACjD,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,iBAAiB,CAC9D,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE;YACxC,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAE1E,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CACnC,GAAG,MAAM,mCAAmC,EAC5C,MAAM,CAAC,QAAQ,EAAE,CAClB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["// @vitest-environment node\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { clerkProvider } from \"./clerk.js\";\n\nafterEach(() => vi.restoreAllMocks());\n\nfunction doc(issuer: string) {\n return {\n issuer,\n authorization_endpoint: `${issuer}/oauth/authorize`,\n token_endpoint: `${issuer}/oauth/token`,\n registration_endpoint: `${issuer}/oauth/register`,\n response_types_supported: [\"code\"],\n scopes_supported: [\"profile\", \"email\"],\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n };\n}\n\ndescribe(\"clerkProvider\", () => {\n it(\"verifies issuer + JWKS with no audience (Clerk tokens carry no aud)\", async () => {\n const issuer = \"https://acme.clerk.accounts.dev\";\n const fetchSpy = vi.spyOn(globalThis, \"fetch\").mockResolvedValue(\n new Response(JSON.stringify(doc(issuer)), {\n headers: { \"content-type\": \"application/json\" },\n }),\n );\n\n const config = await clerkProvider({ domain: \"acme.clerk.accounts.dev\" });\n\n expect(fetchSpy).toHaveBeenCalledWith(\n `${issuer}/.well-known/openid-configuration`,\n expect.anything(),\n );\n expect(config.verify.issuer).toBe(issuer);\n expect(config.verify.audience).toBeUndefined();\n });\n});\n"]}
@@ -0,0 +1,24 @@
1
+ import type { OAuthMetadata } from "@modelcontextprotocol/sdk/shared/auth.js";
2
+ import type { OAuthConfig } from "../index.js";
3
+ /** Options accepted by {@link customProvider} and the branded providers. */
4
+ export type CustomProviderOptions = {
5
+ issuer: string;
6
+ /** Expected token `aud`. Omit to skip audience verification — only for IdPs
7
+ * that don't bind an audience (e.g. Clerk). Branded providers whose IdP does
8
+ * bind an audience re-require it in their own options. */
9
+ audience?: string;
10
+ /** Omit to let the server infer the resource origin from request headers. */
11
+ baseUrl?: string;
12
+ /** Advertise THIS server as the authorization server (skybridge-as-AS): the
13
+ * served AS metadata `issuer` and the PRM `authorization_servers` use this URL
14
+ * instead of the IdP's. Needed when skybridge must sit in the auth path — Auth0
15
+ * (the `audience` must be baked into `/authorize`) or the Alpic DCR proxy (Alpic
16
+ * injects the registration endpoint). Use the static public URL; `verify.issuer`
17
+ * stays the IdP (the token's real `iss`). */
18
+ serverUrl?: string;
19
+ scopes?: string[];
20
+ requiredScopes?: string[];
21
+ metadataOverrides?: Omit<Partial<OAuthMetadata>, "issuer">;
22
+ };
23
+ /** Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document. */
24
+ export declare function customProvider(opts: CustomProviderOptions): Promise<OAuthConfig>;
@@ -0,0 +1,37 @@
1
+ import { discoverAuthorizationServer, } from "../discovery.js";
2
+ /** Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document. */
3
+ export async function customProvider(opts) {
4
+ const discovered = await discoverAuthorizationServer(opts.issuer);
5
+ // JWKS verification needs a signing-key URL; without it the server can't verify
6
+ // tokens. (`registration_endpoint` is optional per RFC 8414 — a no-DCR IdP simply
7
+ // omits it; a proxy like Alpic, or pre-registered clients, supply registration.)
8
+ if (!discovered.jwks_uri) {
9
+ throw new Error(`${opts.issuer} discovery has no jwks_uri; JWKS verification requires it.`);
10
+ }
11
+ // Overrides adjust only advertised metadata; the trust anchor (issuer, jwks_uri)
12
+ // always comes from validated discovery.
13
+ const { issuer: _issuer, jwks_uri: _jwks, ...overrides } = opts.metadataOverrides ?? {};
14
+ const base = { ...discovered, ...overrides };
15
+ const scopesSupported = opts.scopes ?? base.scopes_supported;
16
+ // serverUrl => skybridge-as-AS: advertise this server's URL as the issuer (and
17
+ // keep the served scopes in sync). The verifier still trusts the IdP's `iss`.
18
+ const oauthMetadata = opts.serverUrl
19
+ ? {
20
+ ...base,
21
+ issuer: opts.serverUrl.replace(/\/$/, ""),
22
+ scopes_supported: scopesSupported,
23
+ }
24
+ : base;
25
+ return {
26
+ baseUrl: opts.baseUrl,
27
+ oauthMetadata,
28
+ verify: {
29
+ issuer: discovered.issuer,
30
+ audience: opts.audience,
31
+ jwksUri: discovered.jwks_uri,
32
+ },
33
+ scopesSupported,
34
+ requiredScopes: opts.requiredScopes,
35
+ };
36
+ }
37
+ //# sourceMappingURL=custom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/custom.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AAwBzB,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAA2B;IAE3B,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAElE,gFAAgF;IAChF,kFAAkF;IAClF,iFAAiF;IACjF,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,MAAM,4DAA4D,CAC3E,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,yCAAyC;IACzC,MAAM,EACJ,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,KAAK,EACf,GAAG,SAAS,EACb,GAAgC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC9D,MAAM,IAAI,GAAuB,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,EAAE,CAAC;IACjE,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAC;IAE7D,+EAA+E;IAC/E,8EAA8E;IAC9E,MAAM,aAAa,GAAuB,IAAI,CAAC,SAAS;QACtD,CAAC,CAAC;YACE,GAAG,IAAI;YACP,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;YACzC,gBAAgB,EAAE,eAAe;SAClC;QACH,CAAC,CAAC,IAAI,CAAC;IAET,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa;QACb,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,UAAU,CAAC,QAAQ;SAC7B;QACD,eAAe;QACf,cAAc,EAAE,IAAI,CAAC,cAAc;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type { OAuthMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport {\n type DiscoveredMetadata,\n discoverAuthorizationServer,\n} from \"../discovery.js\";\nimport type { OAuthConfig } from \"../index.js\";\n\n/** Options accepted by {@link customProvider} and the branded providers. */\nexport type CustomProviderOptions = {\n issuer: string;\n /** Expected token `aud`. Omit to skip audience verification — only for IdPs\n * that don't bind an audience (e.g. Clerk). Branded providers whose IdP does\n * bind an audience re-require it in their own options. */\n audience?: string;\n /** Omit to let the server infer the resource origin from request headers. */\n baseUrl?: string;\n /** Advertise THIS server as the authorization server (skybridge-as-AS): the\n * served AS metadata `issuer` and the PRM `authorization_servers` use this URL\n * instead of the IdP's. Needed when skybridge must sit in the auth path — Auth0\n * (the `audience` must be baked into `/authorize`) or the Alpic DCR proxy (Alpic\n * injects the registration endpoint). Use the static public URL; `verify.issuer`\n * stays the IdP (the token's real `iss`). */\n serverUrl?: string;\n scopes?: string[];\n requiredScopes?: string[];\n metadataOverrides?: Omit<Partial<OAuthMetadata>, \"issuer\">;\n};\n\n/** Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document. */\nexport async function customProvider(\n opts: CustomProviderOptions,\n): Promise<OAuthConfig> {\n const discovered = await discoverAuthorizationServer(opts.issuer);\n\n // JWKS verification needs a signing-key URL; without it the server can't verify\n // tokens. (`registration_endpoint` is optional per RFC 8414 — a no-DCR IdP simply\n // omits it; a proxy like Alpic, or pre-registered clients, supply registration.)\n if (!discovered.jwks_uri) {\n throw new Error(\n `${opts.issuer} discovery has no jwks_uri; JWKS verification requires it.`,\n );\n }\n\n // Overrides adjust only advertised metadata; the trust anchor (issuer, jwks_uri)\n // always comes from validated discovery.\n const {\n issuer: _issuer,\n jwks_uri: _jwks,\n ...overrides\n }: Partial<DiscoveredMetadata> = opts.metadataOverrides ?? {};\n const base: DiscoveredMetadata = { ...discovered, ...overrides };\n const scopesSupported = opts.scopes ?? base.scopes_supported;\n\n // serverUrl => skybridge-as-AS: advertise this server's URL as the issuer (and\n // keep the served scopes in sync). The verifier still trusts the IdP's `iss`.\n const oauthMetadata: DiscoveredMetadata = opts.serverUrl\n ? {\n ...base,\n issuer: opts.serverUrl.replace(/\\/$/, \"\"),\n scopes_supported: scopesSupported,\n }\n : base;\n\n return {\n baseUrl: opts.baseUrl,\n oauthMetadata,\n verify: {\n issuer: discovered.issuer,\n audience: opts.audience,\n jwksUri: discovered.jwks_uri,\n },\n scopesSupported,\n requiredScopes: opts.requiredScopes,\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,107 @@
1
+ // @vitest-environment node
2
+ import http from "node:http";
3
+ import { afterEach, describe, expect, it } from "vitest";
4
+ import { customProvider } from "./custom.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", "profile"],
15
+ jwks_uri: `${origin}/jwks`,
16
+ ...extra,
17
+ };
18
+ }
19
+ // Serves the discovery doc (built from the live origin) at the OIDC well-known path.
20
+ async function serveDiscovery(extra = {}) {
21
+ let origin = "";
22
+ const srv = http.createServer((req, res) => {
23
+ if (req.url !== "/.well-known/openid-configuration") {
24
+ res.writeHead(404).end();
25
+ return;
26
+ }
27
+ res.setHeader("content-type", "application/json");
28
+ res.end(JSON.stringify(doc(origin, extra)));
29
+ });
30
+ await new Promise((resolve) => srv.listen(0, resolve));
31
+ server = srv;
32
+ origin = `http://localhost:${srv.address().port}`;
33
+ return origin;
34
+ }
35
+ describe("customProvider", () => {
36
+ it("builds an OAuthConfig from discovery", async () => {
37
+ const base = await serveDiscovery();
38
+ const config = await customProvider({
39
+ issuer: base,
40
+ audience: "my-api",
41
+ baseUrl: "https://app.example.test",
42
+ scopes: ["openid"],
43
+ });
44
+ expect(config.baseUrl).toBe("https://app.example.test");
45
+ expect(config.verify).toEqual({
46
+ issuer: base,
47
+ audience: "my-api",
48
+ jwksUri: `${base}/jwks`,
49
+ });
50
+ expect(config.scopesSupported).toEqual(["openid"]);
51
+ expect(config.oauthMetadata.registration_endpoint).toBe(`${base}/register`);
52
+ });
53
+ it("ignores a runtime issuer override (keeps the discovered trust anchor)", async () => {
54
+ const base = await serveDiscovery();
55
+ const config = await customProvider({
56
+ issuer: base,
57
+ audience: "a",
58
+ metadataOverrides: { issuer: "https://evil.test" },
59
+ });
60
+ expect(config.verify.issuer).toBe(base);
61
+ expect(config.oauthMetadata.issuer).toBe(base);
62
+ });
63
+ it("ignores a runtime jwks_uri override (keeps the discovered signing keys)", async () => {
64
+ const base = await serveDiscovery();
65
+ const config = await customProvider({
66
+ issuer: base,
67
+ audience: "a",
68
+ metadataOverrides: { jwks_uri: "https://evil.test/keys" },
69
+ });
70
+ expect(config.verify.jwksUri).toBe(`${base}/jwks`);
71
+ });
72
+ it("serves metadata without a registration_endpoint when the IdP has no DCR", async () => {
73
+ const base = await serveDiscovery({ registration_endpoint: undefined });
74
+ const config = await customProvider({ issuer: base, audience: "a" });
75
+ expect(config.oauthMetadata.registration_endpoint).toBeUndefined();
76
+ expect(config.verify.issuer).toBe(base);
77
+ });
78
+ it("throws when discovery has no jwks_uri (token verification needs it)", async () => {
79
+ const base = await serveDiscovery({ jwks_uri: undefined });
80
+ await expect(customProvider({ issuer: base, audience: "a" })).rejects.toThrow(/jwks_uri/);
81
+ });
82
+ it("serverUrl advertises this server as the AS, keeping the IdP as the token issuer", async () => {
83
+ const base = await serveDiscovery();
84
+ const config = await customProvider({
85
+ issuer: base,
86
+ audience: "a",
87
+ serverUrl: "https://app.example.test/",
88
+ scopes: ["openid"],
89
+ });
90
+ // AS metadata + advertised scopes reflect this server.
91
+ expect(config.oauthMetadata.issuer).toBe("https://app.example.test");
92
+ expect(config.oauthMetadata.scopes_supported).toEqual(["openid"]);
93
+ // but the token's issuer is still verified against the IdP.
94
+ expect(config.verify.issuer).toBe(base);
95
+ });
96
+ it("applies metadataOverrides over discovered values", async () => {
97
+ const base = await serveDiscovery();
98
+ const config = await customProvider({
99
+ issuer: base,
100
+ audience: "a",
101
+ baseUrl: "https://app.example.test",
102
+ metadataOverrides: { token_endpoint: "https://override/token" },
103
+ });
104
+ expect(config.oauthMetadata.token_endpoint).toBe("https://override/token");
105
+ });
106
+ });
107
+ //# sourceMappingURL=custom.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/custom.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 { customProvider } from \"./custom.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\", \"profile\"],\n jwks_uri: `${origin}/jwks`,\n ...extra,\n };\n}\n\n// Serves the discovery doc (built from the live origin) at the OIDC well-known path.\nasync function serveDiscovery(extra: Record<string, unknown> = {}) {\n let origin = \"\";\n const srv = http.createServer((req, res) => {\n if (req.url !== \"/.well-known/openid-configuration\") {\n res.writeHead(404).end();\n return;\n }\n res.setHeader(\"content-type\", \"application/json\");\n res.end(JSON.stringify(doc(origin, extra)));\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(\"customProvider\", () => {\n it(\"builds an OAuthConfig from discovery\", async () => {\n const base = await serveDiscovery();\n\n const config = await customProvider({\n issuer: base,\n audience: \"my-api\",\n baseUrl: \"https://app.example.test\",\n scopes: [\"openid\"],\n });\n\n expect(config.baseUrl).toBe(\"https://app.example.test\");\n expect(config.verify).toEqual({\n issuer: base,\n audience: \"my-api\",\n jwksUri: `${base}/jwks`,\n });\n expect(config.scopesSupported).toEqual([\"openid\"]);\n expect(config.oauthMetadata.registration_endpoint).toBe(`${base}/register`);\n });\n\n it(\"ignores a runtime issuer override (keeps the discovered trust anchor)\", async () => {\n const base = await serveDiscovery();\n const config = await customProvider({\n issuer: base,\n audience: \"a\",\n metadataOverrides: { issuer: \"https://evil.test\" } as never,\n });\n expect(config.verify.issuer).toBe(base);\n expect(config.oauthMetadata.issuer).toBe(base);\n });\n\n it(\"ignores a runtime jwks_uri override (keeps the discovered signing keys)\", async () => {\n const base = await serveDiscovery();\n const config = await customProvider({\n issuer: base,\n audience: \"a\",\n metadataOverrides: { jwks_uri: \"https://evil.test/keys\" } as never,\n });\n expect(config.verify.jwksUri).toBe(`${base}/jwks`);\n });\n\n it(\"serves metadata without a registration_endpoint when the IdP has no DCR\", async () => {\n const base = await serveDiscovery({ registration_endpoint: undefined });\n const config = await customProvider({ issuer: base, audience: \"a\" });\n expect(config.oauthMetadata.registration_endpoint).toBeUndefined();\n expect(config.verify.issuer).toBe(base);\n });\n\n it(\"throws when discovery has no jwks_uri (token verification needs it)\", async () => {\n const base = await serveDiscovery({ jwks_uri: undefined });\n await expect(\n customProvider({ issuer: base, audience: \"a\" }),\n ).rejects.toThrow(/jwks_uri/);\n });\n\n it(\"serverUrl advertises this server as the AS, keeping the IdP as the token issuer\", async () => {\n const base = await serveDiscovery();\n const config = await customProvider({\n issuer: base,\n audience: \"a\",\n serverUrl: \"https://app.example.test/\",\n scopes: [\"openid\"],\n });\n // AS metadata + advertised scopes reflect this server.\n expect(config.oauthMetadata.issuer).toBe(\"https://app.example.test\");\n expect(config.oauthMetadata.scopes_supported).toEqual([\"openid\"]);\n // but the token's issuer is still verified against the IdP.\n expect(config.verify.issuer).toBe(base);\n });\n\n it(\"applies metadataOverrides over discovered values\", async () => {\n const base = await serveDiscovery();\n const config = await customProvider({\n issuer: base,\n audience: \"a\",\n baseUrl: \"https://app.example.test\",\n metadataOverrides: { token_endpoint: \"https://override/token\" },\n });\n expect(config.oauthMetadata.token_endpoint).toBe(\"https://override/token\");\n });\n});\n"]}
@@ -0,0 +1,15 @@
1
+ import type { OAuthConfig } from "../index.js";
2
+ import { type CustomProviderOptions } from "./custom.js";
3
+ /**
4
+ * OAuth provider for a Descope MCP Server. `url` is the MCP Server's **Discovery
5
+ * URL** (a.k.a. Issuer) from the console's Connection Information, e.g.
6
+ * `https://api.descope.com/v1/apps/agentic/<projectId>/<mcpServerId>` (or your
7
+ * custom domain). Requires DCR enabled on the MCP Server. For Descope with DCR
8
+ * disabled and Alpic's DCR proxy, use {@link customProvider} with `serverUrl`
9
+ * instead (see `examples/auth-descope-alpic`). The token `audience` defaults to
10
+ * the **Project ID** derived from the URL — Descope binds `aud` to [DCR client
11
+ * id, project id], not the server URL; pass `audience` to override.
12
+ */
13
+ export declare function descopeProvider(opts: {
14
+ url: string;
15
+ } & Omit<CustomProviderOptions, "issuer">): Promise<OAuthConfig>;
@@ -0,0 +1,52 @@
1
+ import { fetchDeclaredIssuer } from "../discovery.js";
2
+ import { customProvider } from "./custom.js";
3
+ /**
4
+ * Derives the Descope Project ID from an MCP Server URL
5
+ * (`…/agentic/<projectId>/<mcpServerId>`). Descope binds the token `aud` to the
6
+ * project id, so it doubles as the audience.
7
+ */
8
+ function projectIdFromUrl(url) {
9
+ const projectId = url.match(/\/agentic\/([^/]+)\/[^/]+/)?.[1];
10
+ if (!projectId) {
11
+ throw new Error(`Could not derive the Descope project id from "${url}"; pass an explicit \`audience\`.`);
12
+ }
13
+ return projectId;
14
+ }
15
+ /**
16
+ * OAuth provider for a Descope MCP Server. `url` is the MCP Server's **Discovery
17
+ * URL** (a.k.a. Issuer) from the console's Connection Information, e.g.
18
+ * `https://api.descope.com/v1/apps/agentic/<projectId>/<mcpServerId>` (or your
19
+ * custom domain). Requires DCR enabled on the MCP Server. For Descope with DCR
20
+ * disabled and Alpic's DCR proxy, use {@link customProvider} with `serverUrl`
21
+ * instead (see `examples/auth-descope-alpic`). The token `audience` defaults to
22
+ * the **Project ID** derived from the URL — Descope binds `aud` to [DCR client
23
+ * id, project id], not the server URL; pass `audience` to override.
24
+ */
25
+ export async function descopeProvider(opts) {
26
+ const { url, audience, ...rest } = opts;
27
+ // Strip a trailing `/.well-known/...` discovery suffix with linear string ops
28
+ // (an anchored `.*`-style regex over the untrusted url risks ReDoS): only when
29
+ // the suffix runs to the end without a query/fragment, matching prior behavior.
30
+ const wellKnownAt = url.indexOf("/.well-known/");
31
+ const base = wellKnownAt !== -1 &&
32
+ !url.includes("?", wellKnownAt) &&
33
+ !url.includes("#", wellKnownAt)
34
+ ? url.slice(0, wellKnownAt)
35
+ : url;
36
+ const serverUrl = base.replace(/\/$/, "");
37
+ // Newer Descope MCP Servers serve discovery under the agentic path but declare
38
+ // the base project as `issuer`; follow that so customProvider's strict RFC 8414
39
+ // self-reference check holds against it. Only follow a same-origin issuer — a
40
+ // cross-origin one is untrusted, so fall back to the configured URL.
41
+ const declared = await fetchDeclaredIssuer(serverUrl);
42
+ const issuer = declared && new URL(declared).origin === new URL(serverUrl).origin
43
+ ? declared
44
+ : serverUrl;
45
+ return customProvider({
46
+ issuer,
47
+ // `aud` is bound to the project id, always carried by the agentic server URL.
48
+ audience: audience ?? projectIdFromUrl(serverUrl),
49
+ ...rest,
50
+ });
51
+ }
52
+ //# sourceMappingURL=descope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descope.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/descope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AAEzE;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,2BAA2B,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,iDAAiD,GAAG,mCAAmC,CACxF,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAA6D;IAE7D,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACxC,8EAA8E;IAC9E,+EAA+E;IAC/E,gFAAgF;IAChF,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,MAAM,IAAI,GACR,WAAW,KAAK,CAAC,CAAC;QAClB,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;QAC/B,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;QAC7B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC;QAC3B,CAAC,CAAC,GAAG,CAAC;IACV,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,+EAA+E;IAC/E,gFAAgF;IAChF,8EAA8E;IAC9E,qEAAqE;IACrE,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,QAAQ,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM;QAChE,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,SAAS,CAAC;IAChB,OAAO,cAAc,CAAC;QACpB,MAAM;QACN,8EAA8E;QAC9E,QAAQ,EAAE,QAAQ,IAAI,gBAAgB,CAAC,SAAS,CAAC;QACjD,GAAG,IAAI;KACR,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { fetchDeclaredIssuer } from \"../discovery.js\";\nimport type { OAuthConfig } from \"../index.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\n\n/**\n * Derives the Descope Project ID from an MCP Server URL\n * (`…/agentic/<projectId>/<mcpServerId>`). Descope binds the token `aud` to the\n * project id, so it doubles as the audience.\n */\nfunction projectIdFromUrl(url: string): string {\n const projectId = url.match(/\\/agentic\\/([^/]+)\\/[^/]+/)?.[1];\n if (!projectId) {\n throw new Error(\n `Could not derive the Descope project id from \"${url}\"; pass an explicit \\`audience\\`.`,\n );\n }\n return projectId;\n}\n\n/**\n * OAuth provider for a Descope MCP Server. `url` is the MCP Server's **Discovery\n * URL** (a.k.a. Issuer) from the console's Connection Information, e.g.\n * `https://api.descope.com/v1/apps/agentic/<projectId>/<mcpServerId>` (or your\n * custom domain). Requires DCR enabled on the MCP Server. For Descope with DCR\n * disabled and Alpic's DCR proxy, use {@link customProvider} with `serverUrl`\n * instead (see `examples/auth-descope-alpic`). The token `audience` defaults to\n * the **Project ID** derived from the URL — Descope binds `aud` to [DCR client\n * id, project id], not the server URL; pass `audience` to override.\n */\nexport async function descopeProvider(\n opts: { url: string } & Omit<CustomProviderOptions, \"issuer\">,\n): Promise<OAuthConfig> {\n const { url, audience, ...rest } = opts;\n // Strip a trailing `/.well-known/...` discovery suffix with linear string ops\n // (an anchored `.*`-style regex over the untrusted url risks ReDoS): only when\n // the suffix runs to the end without a query/fragment, matching prior behavior.\n const wellKnownAt = url.indexOf(\"/.well-known/\");\n const base =\n wellKnownAt !== -1 &&\n !url.includes(\"?\", wellKnownAt) &&\n !url.includes(\"#\", wellKnownAt)\n ? url.slice(0, wellKnownAt)\n : url;\n const serverUrl = base.replace(/\\/$/, \"\");\n // Newer Descope MCP Servers serve discovery under the agentic path but declare\n // the base project as `issuer`; follow that so customProvider's strict RFC 8414\n // self-reference check holds against it. Only follow a same-origin issuer — a\n // cross-origin one is untrusted, so fall back to the configured URL.\n const declared = await fetchDeclaredIssuer(serverUrl);\n const issuer =\n declared && new URL(declared).origin === new URL(serverUrl).origin\n ? declared\n : serverUrl;\n return customProvider({\n issuer,\n // `aud` is bound to the project id, always carried by the agentic server URL.\n audience: audience ?? projectIdFromUrl(serverUrl),\n ...rest,\n });\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ // @vitest-environment node
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { descopeProvider } from "./descope.js";
4
+ afterEach(() => vi.restoreAllMocks());
5
+ function discoveryDoc(issuer) {
6
+ return {
7
+ issuer,
8
+ authorization_endpoint: `${issuer}/authorize`,
9
+ token_endpoint: `${issuer}/token`,
10
+ registration_endpoint: `${issuer}/register`,
11
+ response_types_supported: ["code"],
12
+ scopes_supported: ["openid"],
13
+ jwks_uri: `${issuer}/.well-known/jwks.json`,
14
+ };
15
+ }
16
+ function mockDiscovery(issuer) {
17
+ // A fresh Response per call: the provider fetches discovery twice (to read the
18
+ // declared issuer, then again inside customProvider), and a body reads once.
19
+ return vi.spyOn(globalThis, "fetch").mockImplementation(async () => new Response(JSON.stringify(discoveryDoc(issuer)), {
20
+ headers: { "content-type": "application/json" },
21
+ }));
22
+ }
23
+ describe("descopeProvider", () => {
24
+ it("derives issuer and audience (project id) from the MCP Server URL", async () => {
25
+ const issuer = "https://api.descope.com/v1/apps/agentic/P123/MS456";
26
+ const fetchSpy = mockDiscovery(issuer);
27
+ const config = await descopeProvider({ url: issuer });
28
+ expect(fetchSpy).toHaveBeenCalledWith(`${issuer}/.well-known/openid-configuration`, expect.anything());
29
+ expect(config.verify.issuer).toBe(issuer);
30
+ expect(config.verify.audience).toBe("P123");
31
+ });
32
+ it("lets an explicit audience override the derived project id", async () => {
33
+ const issuer = "https://api.descope.com/v1/apps/agentic/P123/MS456";
34
+ mockDiscovery(issuer);
35
+ const config = await descopeProvider({ url: issuer, audience: "custom" });
36
+ expect(config.verify.audience).toBe("custom");
37
+ });
38
+ it("follows a same-origin base-project issuer declared by the discovery doc", async () => {
39
+ // Newer MCP Servers serve discovery at the agentic path but declare the base
40
+ // project as issuer; the resolved issuer follows it (RFC 8414 self-reference
41
+ // then holds), while the audience stays the project id from the agentic URL.
42
+ const url = "https://api.descope.com/v1/apps/agentic/P123/MS456";
43
+ const base = "https://api.descope.com/v1/apps/P123";
44
+ mockDiscovery(base);
45
+ const config = await descopeProvider({ url });
46
+ expect(config.verify.issuer).toBe(base);
47
+ expect(config.verify.audience).toBe("P123");
48
+ expect(config.verify.jwksUri).toBe(`${base}/.well-known/jwks.json`);
49
+ });
50
+ it("does not follow a cross-origin declared issuer", async () => {
51
+ const url = "https://api.descope.com/v1/apps/agentic/P123/MS456";
52
+ const evil = "https://evil.test/v1/apps/P123";
53
+ const fetchSpy = mockDiscovery(evil);
54
+ // The cross-origin issuer is not followed, so discovery is re-run against the
55
+ // configured URL, where the doc's issuer no longer matches — startup fails
56
+ // rather than redirecting trust to evil.test.
57
+ await expect(descopeProvider({ url })).rejects.toThrow(/discovery failed/i);
58
+ expect(fetchSpy).not.toHaveBeenCalledWith(expect.stringContaining("evil.test"), expect.anything());
59
+ });
60
+ });
61
+ //# sourceMappingURL=descope.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descope.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/descope.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO;QACL,MAAM;QACN,sBAAsB,EAAE,GAAG,MAAM,YAAY;QAC7C,cAAc,EAAE,GAAG,MAAM,QAAQ;QACjC,qBAAqB,EAAE,GAAG,MAAM,WAAW;QAC3C,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,gBAAgB,EAAE,CAAC,QAAQ,CAAC;QAC5B,QAAQ,EAAE,GAAG,MAAM,wBAAwB;KAC5C,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,MAAc;IACnC,+EAA+E;IAC/E,6EAA6E;IAC7E,OAAO,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,kBAAkB,CACrD,KAAK,IAAI,EAAE,CACT,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE;QACjD,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CACL,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,MAAM,MAAM,GAAG,oDAAoD,CAAC;QACpE,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QAEvC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAEtD,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CACnC,GAAG,MAAM,mCAAmC,EAC5C,MAAM,CAAC,QAAQ,EAAE,CAClB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,MAAM,GAAG,oDAAoD,CAAC;QACpE,aAAa,CAAC,MAAM,CAAC,CAAC;QAEtB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAE1E,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,6EAA6E;QAC7E,6EAA6E;QAC7E,6EAA6E;QAC7E,MAAM,GAAG,GAAG,oDAAoD,CAAC;QACjE,MAAM,IAAI,GAAG,sCAAsC,CAAC;QACpD,aAAa,CAAC,IAAI,CAAC,CAAC;QAEpB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAE9C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,wBAAwB,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,GAAG,GAAG,oDAAoD,CAAC;QACjE,MAAM,IAAI,GAAG,gCAAgC,CAAC;QAC9C,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAErC,8EAA8E;QAC9E,2EAA2E;QAC3E,8CAA8C;QAC9C,MAAM,MAAM,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAC5E,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,oBAAoB,CACvC,MAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,EACpC,MAAM,CAAC,QAAQ,EAAE,CAClB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["// @vitest-environment node\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { descopeProvider } from \"./descope.js\";\n\nafterEach(() => vi.restoreAllMocks());\n\nfunction discoveryDoc(issuer: string) {\n return {\n issuer,\n authorization_endpoint: `${issuer}/authorize`,\n token_endpoint: `${issuer}/token`,\n registration_endpoint: `${issuer}/register`,\n response_types_supported: [\"code\"],\n scopes_supported: [\"openid\"],\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n };\n}\n\nfunction mockDiscovery(issuer: string) {\n // A fresh Response per call: the provider fetches discovery twice (to read the\n // declared issuer, then again inside customProvider), and a body reads once.\n return vi.spyOn(globalThis, \"fetch\").mockImplementation(\n async () =>\n new Response(JSON.stringify(discoveryDoc(issuer)), {\n headers: { \"content-type\": \"application/json\" },\n }),\n );\n}\n\ndescribe(\"descopeProvider\", () => {\n it(\"derives issuer and audience (project id) from the MCP Server URL\", async () => {\n const issuer = \"https://api.descope.com/v1/apps/agentic/P123/MS456\";\n const fetchSpy = mockDiscovery(issuer);\n\n const config = await descopeProvider({ url: issuer });\n\n expect(fetchSpy).toHaveBeenCalledWith(\n `${issuer}/.well-known/openid-configuration`,\n expect.anything(),\n );\n expect(config.verify.issuer).toBe(issuer);\n expect(config.verify.audience).toBe(\"P123\");\n });\n\n it(\"lets an explicit audience override the derived project id\", async () => {\n const issuer = \"https://api.descope.com/v1/apps/agentic/P123/MS456\";\n mockDiscovery(issuer);\n\n const config = await descopeProvider({ url: issuer, audience: \"custom\" });\n\n expect(config.verify.audience).toBe(\"custom\");\n });\n\n it(\"follows a same-origin base-project issuer declared by the discovery doc\", async () => {\n // Newer MCP Servers serve discovery at the agentic path but declare the base\n // project as issuer; the resolved issuer follows it (RFC 8414 self-reference\n // then holds), while the audience stays the project id from the agentic URL.\n const url = \"https://api.descope.com/v1/apps/agentic/P123/MS456\";\n const base = \"https://api.descope.com/v1/apps/P123\";\n mockDiscovery(base);\n\n const config = await descopeProvider({ url });\n\n expect(config.verify.issuer).toBe(base);\n expect(config.verify.audience).toBe(\"P123\");\n expect(config.verify.jwksUri).toBe(`${base}/.well-known/jwks.json`);\n });\n\n it(\"does not follow a cross-origin declared issuer\", async () => {\n const url = \"https://api.descope.com/v1/apps/agentic/P123/MS456\";\n const evil = \"https://evil.test/v1/apps/P123\";\n const fetchSpy = mockDiscovery(evil);\n\n // The cross-origin issuer is not followed, so discovery is re-run against the\n // configured URL, where the doc's issuer no longer matches — startup fails\n // rather than redirecting trust to evil.test.\n await expect(descopeProvider({ url })).rejects.toThrow(/discovery failed/i);\n expect(fetchSpy).not.toHaveBeenCalledWith(\n expect.stringContaining(\"evil.test\"),\n expect.anything(),\n );\n });\n});\n"]}
@@ -0,0 +1,2 @@
1
+ /** Normalises a bare host to an https issuer URL and strips a trailing slash. */
2
+ export declare function toIssuerUrl(domain: string): string;
@@ -0,0 +1,6 @@
1
+ /** Normalises a bare host to an https issuer URL and strips a trailing slash. */
2
+ export function toIssuerUrl(domain) {
3
+ const withScheme = /^https?:\/\//.test(domain) ? domain : `https://${domain}`;
4
+ return withScheme.replace(/\/$/, "");
5
+ }
6
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/shared.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,MAAM,EAAE,CAAC;IAC9E,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC","sourcesContent":["/** Normalises a bare host to an https issuer URL and strips a trailing slash. */\nexport function toIssuerUrl(domain: string): string {\n const withScheme = /^https?:\\/\\//.test(domain) ? domain : `https://${domain}`;\n return withScheme.replace(/\\/$/, \"\");\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { toIssuerUrl } from "./shared.js";
3
+ describe("toIssuerUrl", () => {
4
+ it("adds https to a bare host, preserves an explicit scheme, strips a trailing slash", () => {
5
+ expect(toIssuerUrl("acme.authkit.app")).toBe("https://acme.authkit.app");
6
+ expect(toIssuerUrl("https://acme.authkit.app/")).toBe("https://acme.authkit.app");
7
+ expect(toIssuerUrl("http://localhost:3000")).toBe("http://localhost:3000");
8
+ });
9
+ });
10
+ //# sourceMappingURL=shared.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/shared.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,kFAAkF,EAAE,GAAG,EAAE;QAC1F,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACzE,MAAM,CAAC,WAAW,CAAC,2BAA2B,CAAC,CAAC,CAAC,IAAI,CACnD,0BAA0B,CAC3B,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { toIssuerUrl } from \"./shared.js\";\n\ndescribe(\"toIssuerUrl\", () => {\n it(\"adds https to a bare host, preserves an explicit scheme, strips a trailing slash\", () => {\n expect(toIssuerUrl(\"acme.authkit.app\")).toBe(\"https://acme.authkit.app\");\n expect(toIssuerUrl(\"https://acme.authkit.app/\")).toBe(\n \"https://acme.authkit.app\",\n );\n expect(toIssuerUrl(\"http://localhost:3000\")).toBe(\"http://localhost:3000\");\n });\n});\n"]}
@@ -0,0 +1,12 @@
1
+ import type { OAuthConfig } from "../index.js";
2
+ import { type CustomProviderOptions } from "./custom.js";
3
+ /**
4
+ * OAuth provider for Stytch Connected Apps. `domain` is the project domain,
5
+ * e.g. `acme.customers.stytch.dev`, or a configured custom domain. Requires
6
+ * DCR enabled in the Stytch dashboard. `audience` is the Stytch Project ID
7
+ * (the default token audience).
8
+ */
9
+ export declare function stytchProvider(opts: {
10
+ domain: string;
11
+ audience: string;
12
+ } & Omit<CustomProviderOptions, "issuer" | "audience">): Promise<OAuthConfig>;
@@ -0,0 +1,13 @@
1
+ import { customProvider } from "./custom.js";
2
+ import { toIssuerUrl } from "./shared.js";
3
+ /**
4
+ * OAuth provider for Stytch Connected Apps. `domain` is the project domain,
5
+ * e.g. `acme.customers.stytch.dev`, or a configured custom domain. Requires
6
+ * DCR enabled in the Stytch dashboard. `audience` is the Stytch Project ID
7
+ * (the default token audience).
8
+ */
9
+ export function stytchProvider(opts) {
10
+ const { domain, ...rest } = opts;
11
+ return customProvider({ issuer: toIssuerUrl(domain), ...rest });
12
+ }
13
+ //# sourceMappingURL=stytch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stytch.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/stytch.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,IAGC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,cAAc,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import type { OAuthConfig } from \"../index.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\nimport { toIssuerUrl } from \"./shared.js\";\n\n/**\n * OAuth provider for Stytch Connected Apps. `domain` is the project domain,\n * e.g. `acme.customers.stytch.dev`, or a configured custom domain. Requires\n * DCR enabled in the Stytch dashboard. `audience` is the Stytch Project ID\n * (the default token audience).\n */\nexport function stytchProvider(\n opts: { domain: string; audience: string } & Omit<\n CustomProviderOptions,\n \"issuer\" | \"audience\"\n >,\n): Promise<OAuthConfig> {\n const { domain, ...rest } = opts;\n return customProvider({ issuer: toIssuerUrl(domain), ...rest });\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import type { OAuthConfig } from "../index.js";
2
+ import { type CustomProviderOptions } from "./custom.js";
3
+ /**
4
+ * OAuth provider for WorkOS AuthKit. `domain` is the AuthKit domain, e.g.
5
+ * `acme.authkit.app`. Requires DCR enabled in the WorkOS dashboard
6
+ * (Connect → Configuration). `audience` is the MCP server's Resource Indicator.
7
+ */
8
+ export declare function workosProvider(opts: {
9
+ domain: string;
10
+ audience: string;
11
+ } & Omit<CustomProviderOptions, "issuer" | "audience">): Promise<OAuthConfig>;
@@ -0,0 +1,12 @@
1
+ import { customProvider } from "./custom.js";
2
+ import { toIssuerUrl } from "./shared.js";
3
+ /**
4
+ * OAuth provider for WorkOS AuthKit. `domain` is the AuthKit domain, e.g.
5
+ * `acme.authkit.app`. Requires DCR enabled in the WorkOS dashboard
6
+ * (Connect → Configuration). `audience` is the MCP server's Resource Indicator.
7
+ */
8
+ export function workosProvider(opts) {
9
+ const { domain, ...rest } = opts;
10
+ return customProvider({ issuer: toIssuerUrl(domain), ...rest });
11
+ }
12
+ //# sourceMappingURL=workos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workos.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/workos.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,IAGC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,cAAc,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import type { OAuthConfig } from \"../index.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\nimport { toIssuerUrl } from \"./shared.js\";\n\n/**\n * OAuth provider for WorkOS AuthKit. `domain` is the AuthKit domain, e.g.\n * `acme.authkit.app`. Requires DCR enabled in the WorkOS dashboard\n * (Connect → Configuration). `audience` is the MCP server's Resource Indicator.\n */\nexport function workosProvider(\n opts: { domain: string; audience: string } & Omit<\n CustomProviderOptions,\n \"issuer\" | \"audience\"\n >,\n): Promise<OAuthConfig> {\n const { domain, ...rest } = opts;\n return customProvider({ issuer: toIssuerUrl(domain), ...rest });\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { Express } from "express";
2
+ import type { OAuthConfig } from "./index.js";
3
+ /** Mounts the well-known OAuth metadata and bearer auth on `/mcp`. */
4
+ export declare function setupOAuth(app: Express, config: OAuthConfig): void;
@@ -0,0 +1,51 @@
1
+ import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter, } from "@modelcontextprotocol/sdk/server/auth/router.js";
2
+ import cors from "cors";
3
+ import { requireBearerAuth } from "../auth.js";
4
+ import { resolveServerOrigin } from "../requestOrigin.js";
5
+ import { createJwksVerifier } from "./verify.js";
6
+ /** Mounts the well-known OAuth metadata and bearer auth on `/mcp`. */
7
+ export function setupOAuth(app, config) {
8
+ if (!config.verify?.issuer) {
9
+ throw new Error("oauth.verify requires an `issuer`");
10
+ }
11
+ const verifier = createJwksVerifier(config.verify);
12
+ // baseUrl known at boot: bake the resource URLs once, no Host-header trust.
13
+ if (config.baseUrl !== undefined) {
14
+ let baseUrl;
15
+ try {
16
+ baseUrl = new URL(config.baseUrl);
17
+ }
18
+ catch {
19
+ throw new Error(`oauth.baseUrl must be a valid absolute URL, got: ${JSON.stringify(config.baseUrl)}`);
20
+ }
21
+ app.use(mcpAuthMetadataRouter({
22
+ oauthMetadata: config.oauthMetadata,
23
+ resourceServerUrl: baseUrl,
24
+ scopesSupported: config.scopesSupported,
25
+ }));
26
+ app.use("/mcp", requireBearerAuth({
27
+ verifier,
28
+ requiredScopes: config.requiredScopes,
29
+ resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(baseUrl),
30
+ }));
31
+ return;
32
+ }
33
+ // No baseUrl: resolve the resource origin per request from forwarded headers
34
+ // (same precedence the framework uses for view serverUrl). Origin headers are
35
+ // pathless, so the PRM path stays at root, matching the SDK's static layout.
36
+ const resolveOrigin = (req) => new URL(resolveServerOrigin((key) => req.get(key)));
37
+ app.use("/.well-known/oauth-authorization-server", cors(), (_req, res) => void res.json(config.oauthMetadata));
38
+ app.use("/.well-known/oauth-protected-resource", cors(), (req, res) => {
39
+ res.json({
40
+ resource: resolveOrigin(req).href,
41
+ authorization_servers: [config.oauthMetadata.issuer],
42
+ scopes_supported: config.scopesSupported,
43
+ });
44
+ });
45
+ app.use("/mcp", (req, res, next) => requireBearerAuth({
46
+ verifier,
47
+ requiredScopes: config.requiredScopes,
48
+ resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(resolveOrigin(req)),
49
+ })(req, res, next));
50
+ }
51
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/server/auth/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oCAAoC,EACpC,qBAAqB,GACtB,MAAM,iDAAiD,CAAC;AACzD,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,sEAAsE;AACtE,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,MAAmB;IAC1D,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAEnD,4EAA4E;IAC5E,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,IAAI,OAAY,CAAC;QACjB,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,oDAAoD,IAAI,CAAC,SAAS,CAChE,MAAM,CAAC,OAAO,CACf,EAAE,CACJ,CAAC;QACJ,CAAC;QACD,GAAG,CAAC,GAAG,CACL,qBAAqB,CAAC;YACpB,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,iBAAiB,EAAE,OAAO;YAC1B,eAAe,EAAE,MAAM,CAAC,eAAe;SACxC,CAAC,CACH,CAAC;QACF,GAAG,CAAC,GAAG,CACL,MAAM,EACN,iBAAiB,CAAC;YAChB,QAAQ;YACR,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,mBAAmB,EAAE,oCAAoC,CAAC,OAAO,CAAC;SACnE,CAAC,CACH,CAAC;QACF,OAAO;IACT,CAAC;IAED,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,MAAM,aAAa,GAAG,CAAC,GAAY,EAAE,EAAE,CACrC,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAEtD,GAAG,CAAC,GAAG,CACL,yCAAyC,EACzC,IAAI,EAAE,EACN,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CACnD,CAAC;IACF,GAAG,CAAC,GAAG,CAAC,uCAAuC,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACpE,GAAG,CAAC,IAAI,CAAC;YACP,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI;YACjC,qBAAqB,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YACpD,gBAAgB,EAAE,MAAM,CAAC,eAAe;SACzC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CACjC,iBAAiB,CAAC;QAChB,QAAQ;QACR,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,mBAAmB,EAAE,oCAAoC,CACvD,aAAa,CAAC,GAAG,CAAC,CACnB;KACF,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CACnB,CAAC;AACJ,CAAC","sourcesContent":["import {\n getOAuthProtectedResourceMetadataUrl,\n mcpAuthMetadataRouter,\n} from \"@modelcontextprotocol/sdk/server/auth/router.js\";\nimport cors from \"cors\";\nimport type { Express, Request } from \"express\";\nimport { requireBearerAuth } from \"../auth.js\";\nimport { resolveServerOrigin } from \"../requestOrigin.js\";\nimport type { OAuthConfig } from \"./index.js\";\nimport { createJwksVerifier } from \"./verify.js\";\n\n/** Mounts the well-known OAuth metadata and bearer auth on `/mcp`. */\nexport function setupOAuth(app: Express, config: OAuthConfig): void {\n if (!config.verify?.issuer) {\n throw new Error(\"oauth.verify requires an `issuer`\");\n }\n\n const verifier = createJwksVerifier(config.verify);\n\n // baseUrl known at boot: bake the resource URLs once, no Host-header trust.\n if (config.baseUrl !== undefined) {\n let baseUrl: URL;\n try {\n baseUrl = new URL(config.baseUrl);\n } catch {\n throw new Error(\n `oauth.baseUrl must be a valid absolute URL, got: ${JSON.stringify(\n config.baseUrl,\n )}`,\n );\n }\n app.use(\n mcpAuthMetadataRouter({\n oauthMetadata: config.oauthMetadata,\n resourceServerUrl: baseUrl,\n scopesSupported: config.scopesSupported,\n }),\n );\n app.use(\n \"/mcp\",\n requireBearerAuth({\n verifier,\n requiredScopes: config.requiredScopes,\n resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(baseUrl),\n }),\n );\n return;\n }\n\n // No baseUrl: resolve the resource origin per request from forwarded headers\n // (same precedence the framework uses for view serverUrl). Origin headers are\n // pathless, so the PRM path stays at root, matching the SDK's static layout.\n const resolveOrigin = (req: Request) =>\n new URL(resolveServerOrigin((key) => req.get(key)));\n\n app.use(\n \"/.well-known/oauth-authorization-server\",\n cors(),\n (_req, res) => void res.json(config.oauthMetadata),\n );\n app.use(\"/.well-known/oauth-protected-resource\", cors(), (req, res) => {\n res.json({\n resource: resolveOrigin(req).href,\n authorization_servers: [config.oauthMetadata.issuer],\n scopes_supported: config.scopesSupported,\n });\n });\n app.use(\"/mcp\", (req, res, next) =>\n requireBearerAuth({\n verifier,\n requiredScopes: config.requiredScopes,\n resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(\n resolveOrigin(req),\n ),\n })(req, res, next),\n );\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};