skybridge 0.0.0-dev.c14a1d3 → 0.0.0-dev.c17120e

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 (395) hide show
  1. package/README.md +17 -14
  2. package/dist/cli/build-helpers.d.ts +6 -2
  3. package/dist/cli/build-helpers.js +39 -14
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +73 -5
  6. package/dist/cli/build-helpers.test.js.map +1 -1
  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.js +0 -1
  13. package/dist/cli/detect-port.js.map +1 -1
  14. package/dist/cli/header.d.ts +1 -1
  15. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  16. package/dist/cli/{resolve-views-dir.js → resolve-skybridge-config.js} +4 -3
  17. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  18. package/dist/cli/run-plain.d.ts +18 -0
  19. package/dist/cli/run-plain.js +90 -0
  20. package/dist/cli/run-plain.js.map +1 -0
  21. package/dist/cli/telemetry.js +2 -0
  22. package/dist/cli/telemetry.js.map +1 -1
  23. package/dist/cli/use-execute-steps.d.ts +1 -1
  24. package/dist/cli/use-nodemon.d.ts +25 -1
  25. package/dist/cli/use-nodemon.js +96 -63
  26. package/dist/cli/use-nodemon.js.map +1 -1
  27. package/dist/cli/use-typescript-check.d.ts +8 -2
  28. package/dist/cli/use-typescript-check.js +70 -67
  29. package/dist/cli/use-typescript-check.js.map +1 -1
  30. package/dist/commands/build.d.ts +0 -2
  31. package/dist/commands/build.js +2 -61
  32. package/dist/commands/build.js.map +1 -1
  33. package/dist/commands/dev.d.ts +1 -0
  34. package/dist/commands/dev.js +38 -6
  35. package/dist/commands/dev.js.map +1 -1
  36. package/dist/commands/start.js +2 -2
  37. package/dist/commands/start.js.map +1 -1
  38. package/dist/context-warnings.d.ts +5 -0
  39. package/dist/context-warnings.js +31 -0
  40. package/dist/context-warnings.js.map +1 -0
  41. package/dist/context-warnings.test.js +28 -0
  42. package/dist/context-warnings.test.js.map +1 -0
  43. package/dist/server/app.d.ts +196 -0
  44. package/dist/server/app.js +279 -0
  45. package/dist/server/app.js.map +1 -0
  46. package/dist/server/app.test.js +231 -0
  47. package/dist/server/app.test.js.map +1 -0
  48. package/dist/server/auth/discovery.d.ts +29 -7
  49. package/dist/server/auth/discovery.js +16 -11
  50. package/dist/server/auth/discovery.js.map +1 -1
  51. package/dist/server/auth/index.d.ts +35 -5
  52. package/dist/server/auth/index.js.map +1 -1
  53. package/dist/server/auth/providers/auth0.d.ts +35 -7
  54. package/dist/server/auth/providers/auth0.js +29 -11
  55. package/dist/server/auth/providers/auth0.js.map +1 -1
  56. package/dist/server/auth/providers/auth0.test.js +31 -14
  57. package/dist/server/auth/providers/auth0.test.js.map +1 -1
  58. package/dist/server/auth/providers/authplane.d.ts +49 -0
  59. package/dist/server/auth/providers/authplane.js +57 -0
  60. package/dist/server/auth/providers/authplane.js.map +1 -0
  61. package/dist/server/auth/providers/authplane.test.js +143 -0
  62. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  63. package/dist/server/auth/providers/clerk.d.ts +44 -5
  64. package/dist/server/auth/providers/clerk.js +9 -8
  65. package/dist/server/auth/providers/clerk.js.map +1 -1
  66. package/dist/server/auth/providers/clerk.test.js +7 -26
  67. package/dist/server/auth/providers/clerk.test.js.map +1 -1
  68. package/dist/server/auth/providers/custom.d.ts +33 -5
  69. package/dist/server/auth/providers/custom.js +46 -15
  70. package/dist/server/auth/providers/custom.js.map +1 -1
  71. package/dist/server/auth/providers/custom.test.js +86 -16
  72. package/dist/server/auth/providers/custom.test.js.map +1 -1
  73. package/dist/server/auth/providers/descope.d.ts +41 -10
  74. package/dist/server/auth/providers/descope.js +38 -8
  75. package/dist/server/auth/providers/descope.js.map +1 -1
  76. package/dist/server/auth/providers/descope.test.js +43 -16
  77. package/dist/server/auth/providers/descope.test.js.map +1 -1
  78. package/dist/server/auth/providers/shared.d.ts +2 -0
  79. package/dist/server/auth/providers/shared.js +6 -0
  80. package/dist/server/auth/providers/shared.js.map +1 -0
  81. package/dist/server/auth/providers/shared.test.js +10 -0
  82. package/dist/server/auth/providers/shared.test.js.map +1 -0
  83. package/dist/server/auth/providers/stytch.d.ts +17 -3
  84. package/dist/server/auth/providers/stytch.js +5 -6
  85. package/dist/server/auth/providers/stytch.js.map +1 -1
  86. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  87. package/dist/server/auth/providers/verify-spy.js +21 -0
  88. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  89. package/dist/server/auth/providers/workos.d.ts +28 -4
  90. package/dist/server/auth/providers/workos.js +7 -7
  91. package/dist/server/auth/providers/workos.js.map +1 -1
  92. package/dist/server/auth/security-schemes.d.ts +23 -0
  93. package/dist/server/auth/security-schemes.js +64 -0
  94. package/dist/server/auth/security-schemes.js.map +1 -0
  95. package/dist/server/auth/security-schemes.test.js +99 -0
  96. package/dist/server/auth/security-schemes.test.js.map +1 -0
  97. package/dist/server/auth/setup.d.ts +3 -1
  98. package/dist/server/auth/setup.js +66 -26
  99. package/dist/server/auth/setup.js.map +1 -1
  100. package/dist/server/auth/setup.test.js +349 -20
  101. package/dist/server/auth/setup.test.js.map +1 -1
  102. package/dist/server/auth/verify.d.ts +42 -5
  103. package/dist/server/auth/verify.js +29 -4
  104. package/dist/server/auth/verify.js.map +1 -1
  105. package/dist/server/auth/verify.test.js +78 -0
  106. package/dist/server/auth/verify.test.js.map +1 -1
  107. package/dist/server/auth-extra.test-d.js +130 -0
  108. package/dist/server/auth-extra.test-d.js.map +1 -0
  109. package/dist/server/auth.d.ts +43 -6
  110. package/dist/server/auth.js +4 -5
  111. package/dist/server/auth.js.map +1 -1
  112. package/dist/server/build-manifest.test.js +7 -6
  113. package/dist/server/build-manifest.test.js.map +1 -1
  114. package/dist/server/content-helpers.d.ts +1 -1
  115. package/dist/server/content-helpers.js.map +1 -1
  116. package/dist/server/events.d.ts +113 -0
  117. package/dist/server/events.js +318 -0
  118. package/dist/server/events.js.map +1 -0
  119. package/dist/server/events.test.d.ts +1 -0
  120. package/dist/server/events.test.js +172 -0
  121. package/dist/server/events.test.js.map +1 -0
  122. package/dist/server/express.d.ts +23 -3
  123. package/dist/server/express.js +43 -32
  124. package/dist/server/express.js.map +1 -1
  125. package/dist/server/express.test.js +221 -103
  126. package/dist/server/express.test.js.map +1 -1
  127. package/dist/server/file-ref.d.ts +1 -1
  128. package/dist/server/file-ref.js +1 -1
  129. package/dist/server/file-ref.js.map +1 -1
  130. package/dist/server/form-input.d.ts +120 -0
  131. package/dist/server/form-input.js +89 -0
  132. package/dist/server/form-input.js.map +1 -0
  133. package/dist/server/host.d.ts +2 -0
  134. package/dist/server/host.js +11 -0
  135. package/dist/server/host.js.map +1 -0
  136. package/dist/server/host.test.d.ts +1 -0
  137. package/dist/server/host.test.js +13 -0
  138. package/dist/server/host.test.js.map +1 -0
  139. package/dist/server/index.d.ts +18 -9
  140. package/dist/server/index.js +11 -3
  141. package/dist/server/index.js.map +1 -1
  142. package/dist/server/mcp-errors.test.d.ts +1 -0
  143. package/dist/server/mcp-errors.test.js +41 -0
  144. package/dist/server/mcp-errors.test.js.map +1 -0
  145. package/dist/server/middleware.d.ts +35 -10
  146. package/dist/server/middleware.js +33 -0
  147. package/dist/server/middleware.js.map +1 -1
  148. package/dist/server/middleware.test-d.js +1 -1
  149. package/dist/server/middleware.test-d.js.map +1 -1
  150. package/dist/server/middleware.test.js +242 -134
  151. package/dist/server/middleware.test.js.map +1 -1
  152. package/dist/server/register-tool.test.d.ts +1 -0
  153. package/dist/server/register-tool.test.js +230 -0
  154. package/dist/server/register-tool.test.js.map +1 -0
  155. package/dist/server/server.d.ts +385 -124
  156. package/dist/server/server.js +506 -348
  157. package/dist/server/server.js.map +1 -1
  158. package/dist/server/skills-integration.test.d.ts +1 -0
  159. package/dist/server/skills-integration.test.js +86 -0
  160. package/dist/server/skills-integration.test.js.map +1 -0
  161. package/dist/server/skills.d.ts +27 -0
  162. package/dist/server/skills.js +188 -0
  163. package/dist/server/skills.js.map +1 -0
  164. package/dist/server/skills.test.d.ts +1 -0
  165. package/dist/server/skills.test.js +243 -0
  166. package/dist/server/skills.test.js.map +1 -0
  167. package/dist/server/templateHelper.d.ts +0 -3
  168. package/dist/server/templateHelper.js.map +1 -1
  169. package/dist/server/templates.generated.js +4 -8
  170. package/dist/server/templates.generated.js.map +1 -1
  171. package/dist/server/tool-extra.test.d.ts +1 -0
  172. package/dist/server/tool-extra.test.js +167 -0
  173. package/dist/server/tool-extra.test.js.map +1 -0
  174. package/dist/server/view-name.test-d.d.ts +1 -0
  175. package/dist/server/view-name.test-d.js +8 -0
  176. package/dist/server/view-name.test-d.js.map +1 -0
  177. package/dist/server/view-resource-resolution.test.js +105 -17
  178. package/dist/server/view-resource-resolution.test.js.map +1 -1
  179. package/dist/server/viewsDevServer.js +4 -1
  180. package/dist/server/viewsDevServer.js.map +1 -1
  181. package/dist/test/utils.d.ts +9 -11
  182. package/dist/test/utils.js +220 -201
  183. package/dist/test/utils.js.map +1 -1
  184. package/dist/test/view.test.js +105 -133
  185. package/dist/test/view.test.js.map +1 -1
  186. package/dist/views/index.d.ts +10 -0
  187. package/dist/views/index.js +3 -0
  188. package/dist/views/index.js.map +1 -0
  189. package/dist/{web/plugin → views}/scan-views.js +1 -1
  190. package/dist/views/scan-views.js.map +1 -0
  191. package/dist/views/scan-views.test.d.ts +1 -0
  192. package/dist/views/scan-views.test.js.map +1 -0
  193. package/dist/views/validate-view.d.ts +1 -0
  194. package/dist/{web/plugin → views}/validate-view.js +2 -2
  195. package/dist/views/validate-view.js.map +1 -0
  196. package/dist/views/validate-view.test.d.ts +1 -0
  197. package/dist/views/validate-view.test.js.map +1 -0
  198. package/dist/web/bridges/adaptor.d.ts +62 -0
  199. package/dist/web/bridges/adaptor.js +477 -0
  200. package/dist/web/bridges/adaptor.js.map +1 -0
  201. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  202. package/dist/web/bridges/adaptor.test.js +281 -0
  203. package/dist/web/bridges/adaptor.test.js.map +1 -0
  204. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -2
  205. package/dist/web/bridges/apps-sdk/bridge.js +15 -4
  206. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  207. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  208. package/dist/web/bridges/apps-sdk/index.js +0 -1
  209. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  210. package/dist/web/bridges/apps-sdk/types.d.ts +2 -3
  211. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  212. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +4 -4
  213. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +4 -4
  214. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  215. package/dist/web/bridges/get-adaptor.d.ts +4 -4
  216. package/dist/web/bridges/get-adaptor.js +6 -11
  217. package/dist/web/bridges/get-adaptor.js.map +1 -1
  218. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  219. package/dist/web/bridges/get-adaptor.test.js +32 -0
  220. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  221. package/dist/web/bridges/mcp-app/bridge.d.ts +14 -3
  222. package/dist/web/bridges/mcp-app/bridge.js +60 -9
  223. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  224. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  225. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  226. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  227. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  228. package/dist/web/bridges/mcp-app/index.js +0 -1
  229. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  230. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  231. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  232. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
  233. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  234. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  235. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  236. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  237. package/dist/web/bridges/mcp-app/view-tools.test.js +6 -7
  238. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  239. package/dist/web/bridges/types.d.ts +83 -15
  240. package/dist/web/bridges/types.js +14 -1
  241. package/dist/web/bridges/types.js.map +1 -1
  242. package/dist/web/bridges/types.test.d.ts +1 -0
  243. package/dist/web/bridges/types.test.js +19 -0
  244. package/dist/web/bridges/types.test.js.map +1 -0
  245. package/dist/web/components/modal-provider.d.ts +1 -1
  246. package/dist/web/components/modal-provider.js +4 -3
  247. package/dist/web/components/modal-provider.js.map +1 -1
  248. package/dist/web/create-store.test.js +10 -7
  249. package/dist/web/create-store.test.js.map +1 -1
  250. package/dist/web/data-llm.d.ts +1 -1
  251. package/dist/web/data-llm.js +3 -2
  252. package/dist/web/data-llm.js.map +1 -1
  253. package/dist/web/data-llm.test.js +26 -7
  254. package/dist/web/data-llm.test.js.map +1 -1
  255. package/dist/web/generate-helpers.d.ts +23 -19
  256. package/dist/web/generate-helpers.js +21 -17
  257. package/dist/web/generate-helpers.js.map +1 -1
  258. package/dist/web/generate-helpers.test-d.js +3 -3
  259. package/dist/web/generate-helpers.test-d.js.map +1 -1
  260. package/dist/web/generate-helpers.test.js +2 -2
  261. package/dist/web/generate-helpers.test.js.map +1 -1
  262. package/dist/web/hooks/index.d.ts +6 -1
  263. package/dist/web/hooks/index.js +6 -1
  264. package/dist/web/hooks/index.js.map +1 -1
  265. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  266. package/dist/web/hooks/openai-extensions.test.js +107 -0
  267. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  268. package/dist/web/hooks/test/utils.d.ts +2 -1
  269. package/dist/web/hooks/test/utils.js +1 -1
  270. package/dist/web/hooks/test/utils.js.map +1 -1
  271. package/dist/web/hooks/use-call-tool.d.ts +2 -2
  272. package/dist/web/hooks/use-call-tool.js +15 -10
  273. package/dist/web/hooks/use-call-tool.js.map +1 -1
  274. package/dist/web/hooks/use-call-tool.test.js +50 -25
  275. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  276. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  277. package/dist/web/hooks/use-deep-link.js +34 -0
  278. package/dist/web/hooks/use-deep-link.js.map +1 -0
  279. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  280. package/dist/web/hooks/use-display-mode.js +1 -1
  281. package/dist/web/hooks/use-display-mode.js.map +1 -1
  282. package/dist/web/hooks/use-display-mode.test.js +57 -21
  283. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  284. package/dist/web/hooks/use-download.d.ts +1 -3
  285. package/dist/web/hooks/use-download.js +1 -2
  286. package/dist/web/hooks/use-download.js.map +1 -1
  287. package/dist/web/hooks/use-download.test.js +18 -10
  288. package/dist/web/hooks/use-download.test.js.map +1 -1
  289. package/dist/web/hooks/use-file-resource.d.ts +37 -0
  290. package/dist/web/hooks/use-file-resource.js +98 -0
  291. package/dist/web/hooks/use-file-resource.js.map +1 -0
  292. package/dist/web/hooks/use-file-resource.test.d.ts +1 -0
  293. package/dist/web/hooks/use-file-resource.test.js +65 -0
  294. package/dist/web/hooks/use-file-resource.test.js.map +1 -0
  295. package/dist/web/hooks/use-files.test.js +11 -3
  296. package/dist/web/hooks/use-files.test.js.map +1 -1
  297. package/dist/web/hooks/use-host.d.ts +44 -0
  298. package/dist/web/hooks/use-host.js +45 -0
  299. package/dist/web/hooks/use-host.js.map +1 -0
  300. package/dist/web/hooks/use-host.test.d.ts +1 -0
  301. package/dist/web/hooks/use-host.test.js +59 -0
  302. package/dist/web/hooks/use-host.test.js.map +1 -0
  303. package/dist/web/hooks/use-model-context.d.ts +44 -0
  304. package/dist/web/hooks/use-model-context.js +63 -0
  305. package/dist/web/hooks/use-model-context.js.map +1 -0
  306. package/dist/web/hooks/use-open-external.test.js +15 -5
  307. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  308. package/dist/web/hooks/use-open-file.d.ts +20 -0
  309. package/dist/web/hooks/use-open-file.js +25 -0
  310. package/dist/web/hooks/use-open-file.js.map +1 -0
  311. package/dist/web/hooks/use-register-view-tool.d.ts +3 -4
  312. package/dist/web/hooks/use-register-view-tool.js +1 -1
  313. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  314. package/dist/web/hooks/use-request-close.test.js +35 -40
  315. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  316. package/dist/web/hooks/use-request-modal.test.js +11 -1
  317. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  318. package/dist/web/hooks/use-request-size.d.ts +1 -1
  319. package/dist/web/hooks/use-request-size.js +1 -1
  320. package/dist/web/hooks/use-request-size.js.map +1 -1
  321. package/dist/web/hooks/use-request-size.test.js +35 -53
  322. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  323. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  324. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  325. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  326. package/dist/web/hooks/use-set-open-in-app-url.test.js +26 -12
  327. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  328. package/dist/web/hooks/use-tool-info.d.ts +1 -20
  329. package/dist/web/hooks/use-tool-info.js +0 -1
  330. package/dist/web/hooks/use-tool-info.js.map +1 -1
  331. package/dist/web/hooks/use-tool-info.test-d.js +0 -5
  332. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  333. package/dist/web/hooks/use-tool-info.test.js +38 -33
  334. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  335. package/dist/web/hooks/use-user.d.ts +3 -2
  336. package/dist/web/hooks/use-user.js +4 -3
  337. package/dist/web/hooks/use-user.js.map +1 -1
  338. package/dist/web/hooks/use-user.test.js +85 -37
  339. package/dist/web/hooks/use-user.test.js.map +1 -1
  340. package/dist/web/hooks/use-view-state.js +19 -9
  341. package/dist/web/hooks/use-view-state.js.map +1 -1
  342. package/dist/web/hooks/use-view-state.test.js +39 -4
  343. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  344. package/dist/web/hooks/use-viewport.d.ts +20 -0
  345. package/dist/web/hooks/use-viewport.js +21 -0
  346. package/dist/web/hooks/use-viewport.js.map +1 -0
  347. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  348. package/dist/web/hooks/use-viewport.test.js +109 -0
  349. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  350. package/dist/web/mount-view.d.ts +3 -2
  351. package/dist/web/mount-view.js +5 -8
  352. package/dist/web/mount-view.js.map +1 -1
  353. package/package.json +34 -29
  354. package/dist/cli/resolve-views-dir.d.ts +0 -1
  355. package/dist/cli/resolve-views-dir.js.map +0 -1
  356. package/dist/server/auth/providers/stytch.test.js +0 -33
  357. package/dist/server/auth/providers/stytch.test.js.map +0 -1
  358. package/dist/server/auth/providers/workos.test.js +0 -41
  359. package/dist/server/auth/providers/workos.test.js.map +0 -1
  360. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -29
  361. package/dist/web/bridges/apps-sdk/adaptor.js +0 -117
  362. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  363. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -53
  364. package/dist/web/bridges/mcp-app/adaptor.js +0 -283
  365. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  366. package/dist/web/hooks/use-layout.d.ts +0 -24
  367. package/dist/web/hooks/use-layout.js +0 -25
  368. package/dist/web/hooks/use-layout.js.map +0 -1
  369. package/dist/web/hooks/use-layout.test.js +0 -96
  370. package/dist/web/hooks/use-layout.test.js.map +0 -1
  371. package/dist/web/plugin/data-llm.test.js +0 -81
  372. package/dist/web/plugin/data-llm.test.js.map +0 -1
  373. package/dist/web/plugin/plugin.d.ts +0 -33
  374. package/dist/web/plugin/plugin.js +0 -189
  375. package/dist/web/plugin/plugin.js.map +0 -1
  376. package/dist/web/plugin/scan-views.js.map +0 -1
  377. package/dist/web/plugin/scan-views.test.js.map +0 -1
  378. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  379. package/dist/web/plugin/transform-data-llm.js +0 -96
  380. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  381. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  382. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  383. package/dist/web/plugin/validate-view.d.ts +0 -1
  384. package/dist/web/plugin/validate-view.js.map +0 -1
  385. package/dist/web/plugin/validate-view.test.js.map +0 -1
  386. /package/dist/{server/auth/providers/stytch.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  387. /package/dist/{server/auth/providers/workos.test.d.ts → context-warnings.test.d.ts} +0 -0
  388. /package/dist/{web/hooks/use-layout.test.d.ts → server/app.test.d.ts} +0 -0
  389. /package/dist/{web/plugin/scan-views.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  390. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/auth/providers/shared.test.d.ts} +0 -0
  391. /package/dist/{web/plugin/validate-view.test.d.ts → server/auth/security-schemes.test.d.ts} +0 -0
  392. /package/dist/{web/plugin/data-llm.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  393. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  394. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  395. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -1,27 +1,58 @@
1
1
  import { discoverAuthorizationServer, } from "../discovery.js";
2
- /** Builds a complete {@link OAuthConfig} for a DCR-compatible IdP via discovery. */
3
- export async function customProvider(opts) {
2
+ import { createJwksVerifier } from "../verify.js";
3
+ /**
4
+ * Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document.
5
+ *
6
+ * @typeParam TExtra - Claims the IdP puts in the access token, reaching handlers
7
+ * as `extra.http?.authInfo.extra`. The branded providers pass their documented claims;
8
+ * pass your own when wiring an IdP by hand.
9
+ */
10
+ export function customProvider(opts) {
11
+ return { resolve: () => resolveCustomProvider(opts) };
12
+ }
13
+ async function resolveCustomProvider(opts) {
4
14
  const discovered = await discoverAuthorizationServer(opts.issuer);
5
- // The IdP's own discovery must advertise DCR and a JWKS; overrides can't fake it.
6
- if (!discovered.registration_endpoint) {
7
- throw new Error(`${opts.issuer} is not DCR-compatible (no registration_endpoint); customProvider only supports DCR IdPs.`);
8
- }
15
+ // JWKS verification needs a signing-key URL; without it the server can't verify
16
+ // tokens. (`registration_endpoint` is optional per RFC 8414 — a no-DCR IdP simply
17
+ // omits it; a proxy like Alpic, or pre-registered clients, supply registration.)
9
18
  if (!discovered.jwks_uri) {
10
19
  throw new Error(`${opts.issuer} discovery has no jwks_uri; JWKS verification requires it.`);
11
20
  }
12
- // Overrides adjust only advertised metadata (e.g. proxied endpoints). The
13
- // trust anchor (issuer, jwks_uri) always comes from validated discovery.
14
- const { issuer: _issuer, jwks_uri: _jwks, ...overrides } = (opts.metadataOverrides ?? {});
15
- const oauthMetadata = { ...discovered, ...overrides };
21
+ // Overrides adjust only advertised metadata; the trust anchor (issuer, jwks_uri)
22
+ // always comes from validated discovery.
23
+ const { issuer: _issuer, jwks_uri: _jwks, ...overrides } = opts.metadataOverrides ?? {};
24
+ let advertised = discovered;
25
+ if (opts.authorizationServer) {
26
+ try {
27
+ advertised = await discoverAuthorizationServer(opts.authorizationServer);
28
+ }
29
+ catch (err) {
30
+ console.warn(`OAuth discovery failed for authorizationServer ${opts.authorizationServer}; advertising ${opts.issuer} metadata instead: ${err instanceof Error ? err.message : String(err)}`);
31
+ }
32
+ }
33
+ const base = { ...advertised, ...overrides };
34
+ const scopesSupported = opts.scopes ?? base.scopes_supported;
35
+ // serverUrl (skybridge-as-AS) overrides the advertised issuer, keeping the
36
+ // IdP as the token issuer. authorizationServer re-asserts its own URL so a
37
+ // failed AS discovery still points clients at the AS. serverUrl wins.
38
+ const advertisedIssuer = opts.serverUrl?.replace(/\/$/, "") ??
39
+ opts.authorizationServer?.replace(/\/$/, "");
40
+ const oauthMetadata = advertisedIssuer
41
+ ? {
42
+ ...base,
43
+ issuer: advertisedIssuer,
44
+ scopes_supported: scopesSupported,
45
+ }
46
+ : base;
16
47
  return {
17
48
  baseUrl: opts.baseUrl,
18
49
  oauthMetadata,
19
- verify: {
20
- issuer: discovered.issuer,
50
+ verifier: createJwksVerifier({
51
+ issuer: advertised.issuer,
21
52
  audience: opts.audience,
22
- jwksUri: discovered.jwks_uri,
23
- },
24
- scopesSupported: opts.scopes ?? oauthMetadata.scopes_supported,
53
+ jwksUri: advertised.jwks_uri ?? discovered.jwks_uri,
54
+ }),
55
+ scopesSupported,
25
56
  requiredScopes: opts.requiredScopes,
26
57
  };
27
58
  }
@@ -1 +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;AAczB,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAA2B;IAE3B,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAElE,kFAAkF;IAClF,IAAI,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,MAAM,2FAA2F,CAC1G,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,MAAM,4DAA4D,CAC3E,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,MAAM,EACJ,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,KAAK,EACf,GAAG,SAAS,EACb,GAAG,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAgC,CAAC;IAClE,MAAM,aAAa,GAAuB,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,EAAE,CAAC;IAE1E,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,EAAE,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC,gBAAgB;QAC9D,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 audience: string;\n /** Omit to let the server infer the resource origin from request headers. */\n baseUrl?: string;\n scopes?: string[];\n requiredScopes?: string[];\n metadataOverrides?: Omit<Partial<OAuthMetadata>, \"issuer\">;\n};\n\n/** Builds a complete {@link OAuthConfig} for a DCR-compatible IdP via discovery. */\nexport async function customProvider(\n opts: CustomProviderOptions,\n): Promise<OAuthConfig> {\n const discovered = await discoverAuthorizationServer(opts.issuer);\n\n // The IdP's own discovery must advertise DCR and a JWKS; overrides can't fake it.\n if (!discovered.registration_endpoint) {\n throw new Error(\n `${opts.issuer} is not DCR-compatible (no registration_endpoint); customProvider only supports DCR IdPs.`,\n );\n }\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 (e.g. proxied endpoints). The\n // trust anchor (issuer, jwks_uri) always comes from validated discovery.\n const {\n issuer: _issuer,\n jwks_uri: _jwks,\n ...overrides\n } = (opts.metadataOverrides ?? {}) as Partial<DiscoveredMetadata>;\n const oauthMetadata: DiscoveredMetadata = { ...discovered, ...overrides };\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: opts.scopes ?? oauthMetadata.scopes_supported,\n requiredScopes: opts.requiredScopes,\n };\n}\n"]}
1
+ {"version":3,"file":"custom.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/custom.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,kBAAkB,EAAyB,MAAM,cAAc,CAAC;AAiCzE;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,IAA2B;IAE3B,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAS,IAAI,CAAC,EAAE,CAAC;AAChE,CAAC;AAED,KAAK,UAAU,qBAAqB,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,IAAI,UAAU,GAAG,UAAU,CAAC;IAC5B,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CACV,kDAAkD,IAAI,CAAC,mBAAmB,iBAAiB,IAAI,CAAC,MAAM,sBAAsB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC/K,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAuB,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,EAAE,CAAC;IACjE,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAC;IAE7D,2EAA2E;IAC3E,2EAA2E;IAC3E,sEAAsE;IACtE,MAAM,gBAAgB,GACpB,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAuB,gBAAgB;QACxD,CAAC,CAAC;YACE,GAAG,IAAI;YACP,MAAM,EAAE,gBAAgB;YACxB,gBAAgB,EAAE,eAAe;SAClC;QACH,CAAC,CAAC,IAAI,CAAC;IAET,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa;QACb,QAAQ,EAAE,kBAAkB,CAAS;YACnC,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ;SACpD,CAAC;QACF,eAAe;QACf,cAAc,EAAE,IAAI,CAAC,cAAc;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type { OAuthMetadata } from \"@modelcontextprotocol/server\";\nimport type { ExtraClaims } from \"../../auth.js\";\nimport {\n type DiscoveredMetadata,\n discoverAuthorizationServer,\n} from \"../discovery.js\";\nimport type { OAuthConfig, OAuthProvider } from \"../index.js\";\nimport { createJwksVerifier, type RegisteredClaims } from \"../verify.js\";\n\n/** Options accepted by {@link customProvider} and the branded providers. */\nexport type CustomProviderOptions = {\n issuer: string;\n /** Expected token `aud`, or several when the server is reached at more than\n * one URL (a local port and a dev tunnel): a token passes when its `aud`\n * matches any of them. 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 | 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 /** Advertise this URL as the authorization server (served AS metadata `issuer`\n * and PRM `authorization_servers`). Its own discovery document supplies the\n * advertised endpoints, DCR registration, scopes and the `iss` tokens are\n * verified against; only `jwks_uri` still comes from `issuer`'s document. Use\n * when DCR/authorize/token live at a different URL than the discovery issuer\n * (e.g. Descope's agentic URL vs. its base-project URL). `serverUrl` wins if\n * both are set. */\n authorizationServer?: string;\n scopes?: string[];\n requiredScopes?: string[];\n metadataOverrides?: Omit<Partial<OAuthMetadata>, \"issuer\">;\n};\n\n/**\n * Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document.\n *\n * @typeParam TExtra - Claims the IdP puts in the access token, reaching handlers\n * as `extra.http?.authInfo.extra`. The branded providers pass their documented claims;\n * pass your own when wiring an IdP by hand.\n */\nexport function customProvider<TExtra extends ExtraClaims = ExtraClaims>(\n opts: CustomProviderOptions,\n): OAuthProvider<TExtra & RegisteredClaims> {\n return { resolve: () => resolveCustomProvider<TExtra>(opts) };\n}\n\nasync function resolveCustomProvider<TExtra extends ExtraClaims>(\n opts: CustomProviderOptions,\n): Promise<OAuthConfig<TExtra & RegisteredClaims>> {\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 let advertised = discovered;\n if (opts.authorizationServer) {\n try {\n advertised = await discoverAuthorizationServer(opts.authorizationServer);\n } catch (err) {\n console.warn(\n `OAuth discovery failed for authorizationServer ${opts.authorizationServer}; advertising ${opts.issuer} metadata instead: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n const base: DiscoveredMetadata = { ...advertised, ...overrides };\n const scopesSupported = opts.scopes ?? base.scopes_supported;\n\n // serverUrl (skybridge-as-AS) overrides the advertised issuer, keeping the\n // IdP as the token issuer. authorizationServer re-asserts its own URL so a\n // failed AS discovery still points clients at the AS. serverUrl wins.\n const advertisedIssuer =\n opts.serverUrl?.replace(/\\/$/, \"\") ??\n opts.authorizationServer?.replace(/\\/$/, \"\");\n const oauthMetadata: DiscoveredMetadata = advertisedIssuer\n ? {\n ...base,\n issuer: advertisedIssuer,\n scopes_supported: scopesSupported,\n }\n : base;\n\n return {\n baseUrl: opts.baseUrl,\n oauthMetadata,\n verifier: createJwksVerifier<TExtra>({\n issuer: advertised.issuer,\n audience: opts.audience,\n jwksUri: advertised.jwks_uri ?? discovered.jwks_uri,\n }),\n scopesSupported,\n requiredScopes: opts.requiredScopes,\n };\n}\n"]}
@@ -1,9 +1,15 @@
1
1
  // @vitest-environment node
2
2
  import http from "node:http";
3
- import { afterEach, describe, expect, it } from "vitest";
3
+ import { afterEach, describe, expect, it, vi } from "vitest";
4
4
  import { customProvider } from "./custom.js";
5
- let server;
6
- afterEach(() => server?.close());
5
+ import { lastJwksConfig as jwks } from "./verify-spy.js";
6
+ vi.mock("../verify.js", () => import("./verify-spy.js"));
7
+ const servers = [];
8
+ afterEach(() => {
9
+ for (const srv of servers.splice(0)) {
10
+ srv.close();
11
+ }
12
+ });
7
13
  function doc(origin, extra = {}) {
8
14
  return {
9
15
  issuer: origin,
@@ -28,7 +34,7 @@ async function serveDiscovery(extra = {}) {
28
34
  res.end(JSON.stringify(doc(origin, extra)));
29
35
  });
30
36
  await new Promise((resolve) => srv.listen(0, resolve));
31
- server = srv;
37
+ servers.push(srv);
32
38
  origin = `http://localhost:${srv.address().port}`;
33
39
  return origin;
34
40
  }
@@ -40,9 +46,9 @@ describe("customProvider", () => {
40
46
  audience: "my-api",
41
47
  baseUrl: "https://app.example.test",
42
48
  scopes: ["openid"],
43
- });
49
+ }).resolve();
44
50
  expect(config.baseUrl).toBe("https://app.example.test");
45
- expect(config.verify).toEqual({
51
+ expect(jwks()).toEqual({
46
52
  issuer: base,
47
53
  audience: "my-api",
48
54
  jwksUri: `${base}/jwks`,
@@ -56,26 +62,90 @@ describe("customProvider", () => {
56
62
  issuer: base,
57
63
  audience: "a",
58
64
  metadataOverrides: { issuer: "https://evil.test" },
59
- });
60
- expect(config.verify.issuer).toBe(base);
65
+ }).resolve();
66
+ expect(jwks().issuer).toBe(base);
61
67
  expect(config.oauthMetadata.issuer).toBe(base);
62
68
  });
63
69
  it("ignores a runtime jwks_uri override (keeps the discovered signing keys)", async () => {
64
70
  const base = await serveDiscovery();
65
- const config = await customProvider({
71
+ await customProvider({
66
72
  issuer: base,
67
73
  audience: "a",
68
74
  metadataOverrides: { jwks_uri: "https://evil.test/keys" },
69
- });
70
- expect(config.verify.jwksUri).toBe(`${base}/jwks`);
75
+ }).resolve();
76
+ expect(jwks().jwksUri).toBe(`${base}/jwks`);
71
77
  });
72
- it("rejects a non-DCR IdP even if an override supplies registration_endpoint", async () => {
78
+ it("serves metadata without a registration_endpoint when the IdP has no DCR", async () => {
73
79
  const base = await serveDiscovery({ registration_endpoint: undefined });
74
- await expect(customProvider({
80
+ const config = await customProvider({
81
+ issuer: base,
82
+ audience: "a",
83
+ }).resolve();
84
+ expect(config.oauthMetadata.registration_endpoint).toBeUndefined();
85
+ expect(jwks().issuer).toBe(base);
86
+ });
87
+ it("throws when discovery has no jwks_uri (token verification needs it)", async () => {
88
+ const base = await serveDiscovery({ jwks_uri: undefined });
89
+ await expect(customProvider({ issuer: base, audience: "a" }).resolve()).rejects.toThrow(/jwks_uri/);
90
+ });
91
+ it("serverUrl advertises this server as the AS, keeping the IdP as the token issuer", async () => {
92
+ const base = await serveDiscovery();
93
+ const config = await customProvider({
75
94
  issuer: base,
76
95
  audience: "a",
77
- metadataOverrides: { registration_endpoint: `${base}/register` },
78
- })).rejects.toThrow(/not DCR-compatible/);
96
+ serverUrl: "https://app.example.test/",
97
+ scopes: ["openid"],
98
+ }).resolve();
99
+ // AS metadata + advertised scopes reflect this server.
100
+ expect(config.oauthMetadata.issuer).toBe("https://app.example.test");
101
+ expect(config.oauthMetadata.scopes_supported).toEqual(["openid"]);
102
+ // but the token's issuer is still verified against the IdP.
103
+ expect(jwks().issuer).toBe(base);
104
+ });
105
+ it("authorizationServer supplies the advertised metadata and the verified issuer", async () => {
106
+ const base = await serveDiscovery();
107
+ const as = await serveDiscovery({ scopes_supported: ["checkout"] });
108
+ const config = await customProvider({
109
+ issuer: base,
110
+ audience: "a",
111
+ authorizationServer: `${as}/`,
112
+ }).resolve();
113
+ expect(config.oauthMetadata.issuer).toBe(as);
114
+ expect(config.oauthMetadata.authorization_endpoint).toBe(`${as}/authorize`);
115
+ expect(config.oauthMetadata.registration_endpoint).toBe(`${as}/register`);
116
+ expect(config.scopesSupported).toEqual(["checkout"]);
117
+ expect(jwks()).toEqual({
118
+ issuer: as,
119
+ audience: "a",
120
+ jwksUri: `${as}/jwks`,
121
+ });
122
+ });
123
+ it("falls back to the issuer's metadata when the authorizationServer is undiscoverable", async () => {
124
+ const base = await serveDiscovery();
125
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
126
+ const config = await customProvider({
127
+ issuer: base,
128
+ audience: "a",
129
+ authorizationServer: `${base}/agentic/P1/MS1`,
130
+ }).resolve();
131
+ expect(warn).toHaveBeenCalledOnce();
132
+ expect(config.oauthMetadata.issuer).toBe(`${base}/agentic/P1/MS1`);
133
+ expect(config.oauthMetadata.authorization_endpoint).toBe(`${base}/authorize`);
134
+ expect(jwks().issuer).toBe(base);
135
+ warn.mockRestore();
136
+ });
137
+ it("serverUrl takes precedence over authorizationServer", async () => {
138
+ const base = await serveDiscovery();
139
+ const as = await serveDiscovery();
140
+ const config = await customProvider({
141
+ issuer: base,
142
+ audience: "a",
143
+ serverUrl: "https://app.example.test/",
144
+ authorizationServer: as,
145
+ }).resolve();
146
+ expect(config.oauthMetadata.issuer).toBe("https://app.example.test");
147
+ expect(config.oauthMetadata.token_endpoint).toBe(`${as}/token`);
148
+ expect(jwks().issuer).toBe(as);
79
149
  });
80
150
  it("applies metadataOverrides over discovered values", async () => {
81
151
  const base = await serveDiscovery();
@@ -84,7 +154,7 @@ describe("customProvider", () => {
84
154
  audience: "a",
85
155
  baseUrl: "https://app.example.test",
86
156
  metadataOverrides: { token_endpoint: "https://override/token" },
87
- });
157
+ }).resolve();
88
158
  expect(config.oauthMetadata.token_endpoint).toBe("https://override/token");
89
159
  });
90
160
  });
@@ -1 +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(\"rejects a non-DCR IdP even if an override supplies registration_endpoint\", async () => {\n const base = await serveDiscovery({ registration_endpoint: undefined });\n await expect(\n customProvider({\n issuer: base,\n audience: \"a\",\n metadataOverrides: { registration_endpoint: `${base}/register` },\n }),\n ).rejects.toThrow(/not DCR-compatible/);\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"]}
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, vi } from \"vitest\";\nimport { customProvider } from \"./custom.js\";\nimport { lastJwksConfig as jwks } from \"./verify-spy.js\";\n\nvi.mock(\"../verify.js\", () => import(\"./verify-spy.js\"));\n\nconst servers: http.Server[] = [];\nafterEach(() => {\n for (const srv of servers.splice(0)) {\n srv.close();\n }\n});\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 servers.push(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 }).resolve();\n\n expect(config.baseUrl).toBe(\"https://app.example.test\");\n expect(jwks()).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 }).resolve();\n expect(jwks().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 await customProvider({\n issuer: base,\n audience: \"a\",\n metadataOverrides: { jwks_uri: \"https://evil.test/keys\" } as never,\n }).resolve();\n expect(jwks().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({\n issuer: base,\n audience: \"a\",\n }).resolve();\n expect(config.oauthMetadata.registration_endpoint).toBeUndefined();\n expect(jwks().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\" }).resolve(),\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 }).resolve();\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(jwks().issuer).toBe(base);\n });\n\n it(\"authorizationServer supplies the advertised metadata and the verified issuer\", async () => {\n const base = await serveDiscovery();\n const as = await serveDiscovery({ scopes_supported: [\"checkout\"] });\n\n const config = await customProvider({\n issuer: base,\n audience: \"a\",\n authorizationServer: `${as}/`,\n }).resolve();\n\n expect(config.oauthMetadata.issuer).toBe(as);\n expect(config.oauthMetadata.authorization_endpoint).toBe(`${as}/authorize`);\n expect(config.oauthMetadata.registration_endpoint).toBe(`${as}/register`);\n expect(config.scopesSupported).toEqual([\"checkout\"]);\n expect(jwks()).toEqual({\n issuer: as,\n audience: \"a\",\n jwksUri: `${as}/jwks`,\n });\n });\n\n it(\"falls back to the issuer's metadata when the authorizationServer is undiscoverable\", async () => {\n const base = await serveDiscovery();\n const warn = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n\n const config = await customProvider({\n issuer: base,\n audience: \"a\",\n authorizationServer: `${base}/agentic/P1/MS1`,\n }).resolve();\n\n expect(warn).toHaveBeenCalledOnce();\n expect(config.oauthMetadata.issuer).toBe(`${base}/agentic/P1/MS1`);\n expect(config.oauthMetadata.authorization_endpoint).toBe(\n `${base}/authorize`,\n );\n expect(jwks().issuer).toBe(base);\n warn.mockRestore();\n });\n\n it(\"serverUrl takes precedence over authorizationServer\", async () => {\n const base = await serveDiscovery();\n const as = await serveDiscovery();\n const config = await customProvider({\n issuer: base,\n audience: \"a\",\n serverUrl: \"https://app.example.test/\",\n authorizationServer: as,\n }).resolve();\n expect(config.oauthMetadata.issuer).toBe(\"https://app.example.test\");\n expect(config.oauthMetadata.token_endpoint).toBe(`${as}/token`);\n expect(jwks().issuer).toBe(as);\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 }).resolve();\n expect(config.oauthMetadata.token_endpoint).toBe(\"https://override/token\");\n });\n});\n"]}
@@ -1,13 +1,44 @@
1
- import type { OAuthConfig } from "../index.js";
1
+ import type { ExtraClaims } from "../../auth.js";
2
+ import type { OAuthProvider } from "../index.js";
3
+ import type { RegisteredClaims } from "../verify.js";
2
4
  import { type CustomProviderOptions } from "./custom.js";
3
5
  /**
4
- * OAuth provider for a Descope MCP Server. `mcpServerId` is the MCP Server's
5
- * ID (the `MS`-prefixed Resource ID from the console's MCP Servers section),
6
- * not a generic Inbound App or client ID. Requires DCR enabled on the MCP
7
- * Server. `audience` is the MCP server URL. Custom-domain Descope tenants
8
- * should use `customProvider({ issuer })` directly with the full discovery URL.
6
+ * Claims a Descope session JWT carries. Roles and permissions are nested per
7
+ * tenant when the project uses tenants, and flat otherwise. `email` arrives only
8
+ * through a Custom Claims flow action or a JWT template.
9
+ *
10
+ * @see https://docs.descope.com/authorization/session-management
11
+ * @see https://docs.descope.com/management/token/jwt-templates
9
12
  */
10
- export declare function descopeProvider(opts: {
11
- projectId: string;
12
- mcpServerId: string;
13
- } & Omit<CustomProviderOptions, "issuer">): Promise<OAuthConfig>;
13
+ export type DescopeClaims = {
14
+ /** Authentication methods used, e.g. `["otp"]`. */
15
+ amr?: string[];
16
+ /** Descope Resource Name: where the token is stored. */
17
+ drn?: string;
18
+ /** The user's active tenant. */
19
+ dct?: string;
20
+ /** Associated tenants, keyed by tenant id. */
21
+ tenants?: Record<string, {
22
+ roles?: string[];
23
+ permissions?: string[];
24
+ }>;
25
+ /** Roles, when the project has no tenants. */
26
+ roles?: string[];
27
+ /** Permissions, when the project has no tenants. */
28
+ permissions?: string[];
29
+ /** Only via a Custom Claims action or JWT template; not a default claim. */
30
+ email?: string;
31
+ };
32
+ /**
33
+ * OAuth provider for a Descope MCP Server. `url` is the MCP Server's **Discovery
34
+ * URL** (a.k.a. Issuer) from the console's Connection Information, e.g.
35
+ * `https://api.descope.com/v1/apps/agentic/<projectId>/<mcpServerId>` (or your
36
+ * custom domain). Requires DCR enabled on the MCP Server. For Descope with DCR
37
+ * disabled and Alpic's DCR proxy, use {@link customProvider} with `serverUrl`
38
+ * instead (see `examples/auth-descope-alpic`). The token `audience` defaults to
39
+ * the **Project ID** derived from the URL — Descope binds `aud` to [DCR client
40
+ * id, project id], not the server URL; pass `audience` to override.
41
+ */
42
+ export declare function descopeProvider<TCustom extends ExtraClaims = Record<never, never>>(opts: {
43
+ url: string;
44
+ } & Omit<CustomProviderOptions, "issuer">): OAuthProvider<DescopeClaims & TCustom & RegisteredClaims>;
@@ -1,14 +1,44 @@
1
1
  import { customProvider } from "./custom.js";
2
2
  /**
3
- * OAuth provider for a Descope MCP Server. `mcpServerId` is the MCP Server's
4
- * ID (the `MS`-prefixed Resource ID from the console's MCP Servers section),
5
- * not a generic Inbound App or client ID. Requires DCR enabled on the MCP
6
- * Server. `audience` is the MCP server URL. Custom-domain Descope tenants
7
- * should use `customProvider({ issuer })` directly with the full discovery URL.
3
+ * Turns the console's Discovery URL into the authorization server's base URL:
4
+ * drops a `/.well-known/openid-configuration` (or `oauth-authorization-server`)
5
+ * suffix, since discovery appends that path itself, and any trailing slash.
6
+ */
7
+ function toAuthorizationServerUrl(discoveryUrl) {
8
+ return discoveryUrl.replace(/\/\.well-known\/[^?#]*$/, "").replace(/\/$/, "");
9
+ }
10
+ /**
11
+ * Derives the Descope Project ID from an MCP Server URL
12
+ * (`…/agentic/<projectId>/<mcpServerId>`). Descope binds the token `aud` to the
13
+ * project id, so it doubles as the audience.
14
+ */
15
+ function projectIdFromUrl(url) {
16
+ const projectId = url.match(/\/agentic\/([^/]+)\/[^/]+/)?.[1];
17
+ if (!projectId) {
18
+ throw new Error(`Could not derive the Descope project id from "${url}"; pass an explicit \`audience\`.`);
19
+ }
20
+ return projectId;
21
+ }
22
+ /**
23
+ * OAuth provider for a Descope MCP Server. `url` is the MCP Server's **Discovery
24
+ * URL** (a.k.a. Issuer) from the console's Connection Information, e.g.
25
+ * `https://api.descope.com/v1/apps/agentic/<projectId>/<mcpServerId>` (or your
26
+ * custom domain). Requires DCR enabled on the MCP Server. For Descope with DCR
27
+ * disabled and Alpic's DCR proxy, use {@link customProvider} with `serverUrl`
28
+ * instead (see `examples/auth-descope-alpic`). The token `audience` defaults to
29
+ * the **Project ID** derived from the URL — Descope binds `aud` to [DCR client
30
+ * id, project id], not the server URL; pass `audience` to override.
8
31
  */
9
32
  export function descopeProvider(opts) {
10
- const { projectId, mcpServerId, ...rest } = opts;
11
- const issuer = `https://api.descope.com/v1/apps/agentic/${projectId}/${mcpServerId}`;
12
- return customProvider({ issuer, ...rest });
33
+ const { url, audience, ...rest } = opts;
34
+ const asUrl = toAuthorizationServerUrl(url);
35
+ const projectId = projectIdFromUrl(asUrl);
36
+ const issuer = `${asUrl.slice(0, asUrl.indexOf("/agentic/"))}/${projectId}`;
37
+ return customProvider({
38
+ issuer,
39
+ audience: audience ?? projectId,
40
+ authorizationServer: asUrl,
41
+ ...rest,
42
+ });
13
43
  }
14
44
  //# sourceMappingURL=descope.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"descope.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/descope.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AAEzE;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,IAGC;IAED,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjD,MAAM,MAAM,GAAG,2CAA2C,SAAS,IAAI,WAAW,EAAE,CAAC;IACrF,OAAO,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["import type { OAuthConfig } from \"../index.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\n\n/**\n * OAuth provider for a Descope MCP Server. `mcpServerId` is the MCP Server's\n * ID (the `MS`-prefixed Resource ID from the console's MCP Servers section),\n * not a generic Inbound App or client ID. Requires DCR enabled on the MCP\n * Server. `audience` is the MCP server URL. Custom-domain Descope tenants\n * should use `customProvider({ issuer })` directly with the full discovery URL.\n */\nexport function descopeProvider(\n opts: { projectId: string; mcpServerId: string } & Omit<\n CustomProviderOptions,\n \"issuer\"\n >,\n): Promise<OAuthConfig> {\n const { projectId, mcpServerId, ...rest } = opts;\n const issuer = `https://api.descope.com/v1/apps/agentic/${projectId}/${mcpServerId}`;\n return customProvider({ issuer, ...rest });\n}\n"]}
1
+ {"version":3,"file":"descope.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/descope.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AA2BzE;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,YAAoB;IACpD,OAAO,YAAY,CAAC,OAAO,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;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,UAAU,eAAe,CAG7B,IAA6D;IAE7D,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACxC,MAAM,KAAK,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;IAC5E,OAAO,cAAc,CAA0B;QAC7C,MAAM;QACN,QAAQ,EAAE,QAAQ,IAAI,SAAS;QAC/B,mBAAmB,EAAE,KAAK;QAC1B,GAAG,IAAI;KACR,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { ExtraClaims } from \"../../auth.js\";\nimport type { OAuthProvider } from \"../index.js\";\nimport type { RegisteredClaims } from \"../verify.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\n\n/**\n * Claims a Descope session JWT carries. Roles and permissions are nested per\n * tenant when the project uses tenants, and flat otherwise. `email` arrives only\n * through a Custom Claims flow action or a JWT template.\n *\n * @see https://docs.descope.com/authorization/session-management\n * @see https://docs.descope.com/management/token/jwt-templates\n */\nexport type DescopeClaims = {\n /** Authentication methods used, e.g. `[\"otp\"]`. */\n amr?: string[];\n /** Descope Resource Name: where the token is stored. */\n drn?: string;\n /** The user's active tenant. */\n dct?: string;\n /** Associated tenants, keyed by tenant id. */\n tenants?: Record<string, { roles?: string[]; permissions?: string[] }>;\n /** Roles, when the project has no tenants. */\n roles?: string[];\n /** Permissions, when the project has no tenants. */\n permissions?: string[];\n /** Only via a Custom Claims action or JWT template; not a default claim. */\n email?: string;\n};\n\n/**\n * Turns the console's Discovery URL into the authorization server's base URL:\n * drops a `/.well-known/openid-configuration` (or `oauth-authorization-server`)\n * suffix, since discovery appends that path itself, and any trailing slash.\n */\nfunction toAuthorizationServerUrl(discoveryUrl: string): string {\n return discoveryUrl.replace(/\\/\\.well-known\\/[^?#]*$/, \"\").replace(/\\/$/, \"\");\n}\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 function descopeProvider<\n TCustom extends ExtraClaims = Record<never, never>,\n>(\n opts: { url: string } & Omit<CustomProviderOptions, \"issuer\">,\n): OAuthProvider<DescopeClaims & TCustom & RegisteredClaims> {\n const { url, audience, ...rest } = opts;\n const asUrl = toAuthorizationServerUrl(url);\n const projectId = projectIdFromUrl(asUrl);\n const issuer = `${asUrl.slice(0, asUrl.indexOf(\"/agentic/\"))}/${projectId}`;\n return customProvider<DescopeClaims & TCustom>({\n issuer,\n audience: audience ?? projectId,\n authorizationServer: asUrl,\n ...rest,\n });\n}\n"]}
@@ -1,35 +1,62 @@
1
1
  // @vitest-environment node
2
2
  import { afterEach, describe, expect, it, vi } from "vitest";
3
3
  import { descopeProvider } from "./descope.js";
4
+ import { lastJwksConfig as jwks } from "./verify-spy.js";
5
+ vi.mock("../verify.js", () => import("./verify-spy.js"));
4
6
  afterEach(() => vi.restoreAllMocks());
5
- function discoveryDoc(issuer) {
7
+ function discoveryDoc(issuer, scopes) {
6
8
  return {
7
9
  issuer,
8
10
  authorization_endpoint: `${issuer}/authorize`,
9
11
  token_endpoint: `${issuer}/token`,
10
12
  registration_endpoint: `${issuer}/register`,
11
13
  response_types_supported: ["code"],
12
- scopes_supported: ["openid"],
14
+ scopes_supported: scopes,
13
15
  jwks_uri: `${issuer}/.well-known/jwks.json`,
14
16
  };
15
17
  }
16
- function mockDiscovery(issuer) {
17
- return vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(JSON.stringify(discoveryDoc(issuer)), {
18
- headers: { "content-type": "application/json" },
19
- }));
18
+ const PROJECT = "https://api.descope.com/v1/apps/P123";
19
+ const AGENTIC = "https://api.descope.com/v1/apps/agentic/P123/MS456";
20
+ function mockDiscovery(docs) {
21
+ return vi
22
+ .spyOn(globalThis, "fetch")
23
+ .mockImplementation(async (input) => {
24
+ const url = String(input);
25
+ const entry = Object.entries(docs).find(([issuer]) => url === `${issuer}/.well-known/openid-configuration`);
26
+ if (entry === undefined) {
27
+ return new Response(null, { status: 404 });
28
+ }
29
+ return new Response(JSON.stringify(discoveryDoc(...entry)), {
30
+ headers: { "content-type": "application/json" },
31
+ });
32
+ });
20
33
  }
21
34
  describe("descopeProvider", () => {
22
- it("builds the MCP Server issuer from projectId and mcpServerId", async () => {
23
- const issuer = "https://api.descope.com/v1/apps/agentic/P123/MS456";
24
- const fetchSpy = mockDiscovery(issuer);
25
- const config = await descopeProvider({
26
- projectId: "P123",
27
- mcpServerId: "MS456",
28
- audience: "https://mcp.example.com",
35
+ it("verifies against the agentic issuer it advertises", async () => {
36
+ const fetchSpy = mockDiscovery({
37
+ [PROJECT]: ["openid", "profile", "email", "phone"],
38
+ [AGENTIC]: ["checkout"],
29
39
  });
30
- expect(fetchSpy).toHaveBeenCalledWith(`${issuer}/.well-known/openid-configuration`, expect.anything());
31
- expect(config.verify.issuer).toBe(issuer);
32
- expect(config.verify.audience).toBe("https://mcp.example.com");
40
+ const config = await descopeProvider({ url: AGENTIC }).resolve();
41
+ expect(fetchSpy).toHaveBeenCalledWith(`${PROJECT}/.well-known/openid-configuration`, expect.anything());
42
+ expect(jwks().issuer).toBe(AGENTIC);
43
+ expect(jwks().audience).toBe("P123");
44
+ expect(config.oauthMetadata.issuer).toBe(AGENTIC);
45
+ expect(config.oauthMetadata.registration_endpoint).toBe(`${AGENTIC}/register`);
46
+ expect(config.scopesSupported).toEqual(["checkout"]);
47
+ });
48
+ it("accepts a URL carrying the well-known suffix", async () => {
49
+ mockDiscovery({ [PROJECT]: ["openid"], [AGENTIC]: ["checkout"] });
50
+ const config = await descopeProvider({
51
+ url: `${AGENTIC}/.well-known/openid-configuration`,
52
+ }).resolve();
53
+ expect(config.oauthMetadata.issuer).toBe(AGENTIC);
54
+ expect(config.scopesSupported).toEqual(["checkout"]);
55
+ });
56
+ it("lets an explicit audience override the derived project id", async () => {
57
+ mockDiscovery({ [PROJECT]: ["openid"], [AGENTIC]: ["checkout"] });
58
+ await descopeProvider({ url: AGENTIC, audience: "custom" }).resolve();
59
+ expect(jwks().audience).toBe("custom");
33
60
  });
34
61
  });
35
62
  //# sourceMappingURL=descope.test.js.map
@@ -1 +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,OAAO,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,iBAAiB,CACpD,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE;QACjD,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CACH,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,MAAM,GAAG,oDAAoD,CAAC;QACpE,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QAEvC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;YACnC,SAAS,EAAE,MAAM;YACjB,WAAW,EAAE,OAAO;YACpB,QAAQ,EAAE,yBAAyB;SACpC,CAAC,CAAC;QAEH,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,yBAAyB,CAAC,CAAC;IACjE,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 return vi.spyOn(globalThis, \"fetch\").mockResolvedValue(\n new Response(JSON.stringify(discoveryDoc(issuer)), {\n headers: { \"content-type\": \"application/json\" },\n }),\n );\n}\n\ndescribe(\"descopeProvider\", () => {\n it(\"builds the MCP Server issuer from projectId and mcpServerId\", async () => {\n const issuer = \"https://api.descope.com/v1/apps/agentic/P123/MS456\";\n const fetchSpy = mockDiscovery(issuer);\n\n const config = await descopeProvider({\n projectId: \"P123\",\n mcpServerId: \"MS456\",\n audience: \"https://mcp.example.com\",\n });\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(\"https://mcp.example.com\");\n });\n});\n"]}
1
+ {"version":3,"file":"descope.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/descope.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { descopeProvider } from \"./descope.js\";\nimport { lastJwksConfig as jwks } from \"./verify-spy.js\";\n\nvi.mock(\"../verify.js\", () => import(\"./verify-spy.js\"));\n\nafterEach(() => vi.restoreAllMocks());\n\nfunction discoveryDoc(issuer: string, scopes: 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: scopes,\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n };\n}\n\nconst PROJECT = \"https://api.descope.com/v1/apps/P123\";\nconst AGENTIC = \"https://api.descope.com/v1/apps/agentic/P123/MS456\";\n\nfunction mockDiscovery(docs: Record<string, string[]>) {\n return vi\n .spyOn(globalThis, \"fetch\")\n .mockImplementation(async (input: RequestInfo | URL) => {\n const url = String(input);\n const entry = Object.entries(docs).find(\n ([issuer]) => url === `${issuer}/.well-known/openid-configuration`,\n );\n if (entry === undefined) {\n return new Response(null, { status: 404 });\n }\n return new Response(JSON.stringify(discoveryDoc(...entry)), {\n headers: { \"content-type\": \"application/json\" },\n });\n });\n}\n\ndescribe(\"descopeProvider\", () => {\n it(\"verifies against the agentic issuer it advertises\", async () => {\n const fetchSpy = mockDiscovery({\n [PROJECT]: [\"openid\", \"profile\", \"email\", \"phone\"],\n [AGENTIC]: [\"checkout\"],\n });\n\n const config = await descopeProvider({ url: AGENTIC }).resolve();\n\n expect(fetchSpy).toHaveBeenCalledWith(\n `${PROJECT}/.well-known/openid-configuration`,\n expect.anything(),\n );\n expect(jwks().issuer).toBe(AGENTIC);\n expect(jwks().audience).toBe(\"P123\");\n expect(config.oauthMetadata.issuer).toBe(AGENTIC);\n expect(config.oauthMetadata.registration_endpoint).toBe(\n `${AGENTIC}/register`,\n );\n expect(config.scopesSupported).toEqual([\"checkout\"]);\n });\n\n it(\"accepts a URL carrying the well-known suffix\", async () => {\n mockDiscovery({ [PROJECT]: [\"openid\"], [AGENTIC]: [\"checkout\"] });\n\n const config = await descopeProvider({\n url: `${AGENTIC}/.well-known/openid-configuration`,\n }).resolve();\n\n expect(config.oauthMetadata.issuer).toBe(AGENTIC);\n expect(config.scopesSupported).toEqual([\"checkout\"]);\n });\n\n it(\"lets an explicit audience override the derived project id\", async () => {\n mockDiscovery({ [PROJECT]: [\"openid\"], [AGENTIC]: [\"checkout\"] });\n\n await descopeProvider({ url: AGENTIC, audience: \"custom\" }).resolve();\n\n expect(jwks().audience).toBe(\"custom\");\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,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"]}
@@ -1,11 +1,25 @@
1
- import type { OAuthConfig } from "../index.js";
1
+ import type { ExtraClaims } from "../../auth.js";
2
+ import type { OAuthProvider } from "../index.js";
3
+ import type { RegisteredClaims } from "../verify.js";
2
4
  import { type CustomProviderOptions } from "./custom.js";
5
+ /**
6
+ * Claims a Stytch Connected Apps access token carries. Beyond the subject,
7
+ * everything is project-configured through the client's access-token template.
8
+ *
9
+ * @see https://stytch.com/docs/api-reference/consumer/api/connected-apps/tokens/connected-app-access-token-object
10
+ * @see https://stytch.com/docs/api/connected-apps-create
11
+ */
12
+ export type StytchClaims = {
13
+ /** Only when the client's access-token template adds it. */
14
+ email?: string;
15
+ };
3
16
  /**
4
17
  * OAuth provider for Stytch Connected Apps. `domain` is the project domain,
5
18
  * e.g. `acme.customers.stytch.dev`, or a configured custom domain. Requires
6
19
  * DCR enabled in the Stytch dashboard. `audience` is the Stytch Project ID
7
20
  * (the default token audience).
8
21
  */
9
- export declare function stytchProvider(opts: {
22
+ export declare function stytchProvider<TCustom extends ExtraClaims = Record<never, never>>(opts: {
10
23
  domain: string;
11
- } & Omit<CustomProviderOptions, "issuer">): Promise<OAuthConfig>;
24
+ audience: string;
25
+ } & Omit<CustomProviderOptions, "issuer" | "audience">): OAuthProvider<StytchClaims & TCustom & RegisteredClaims>;