skybridge 0.0.0-dev.9c6d6b4 → 0.0.0-dev.9c70f50

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 (321) hide show
  1. package/README.md +16 -14
  2. package/dist/cli/build-helpers.d.ts +1 -1
  3. package/dist/cli/build-helpers.js +4 -4
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +2 -2
  6. package/dist/cli/build-helpers.test.js.map +1 -1
  7. package/dist/cli/build-steps.js +1 -1
  8. package/dist/cli/build-steps.js.map +1 -1
  9. package/dist/cli/build-steps.test.js +3 -3
  10. package/dist/cli/build-steps.test.js.map +1 -1
  11. package/dist/cli/detect-port.js +0 -1
  12. package/dist/cli/detect-port.js.map +1 -1
  13. package/dist/cli/run-plain.js +2 -1
  14. package/dist/cli/run-plain.js.map +1 -1
  15. package/dist/cli/telemetry.js +2 -0
  16. package/dist/cli/telemetry.js.map +1 -1
  17. package/dist/cli/use-execute-steps.d.ts +1 -1
  18. package/dist/cli/use-nodemon.d.ts +11 -1
  19. package/dist/cli/use-nodemon.js +30 -8
  20. package/dist/cli/use-nodemon.js.map +1 -1
  21. package/dist/cli/use-typescript-check.js +1 -1
  22. package/dist/cli/use-typescript-check.js.map +1 -1
  23. package/dist/commands/dev.js +4 -4
  24. package/dist/commands/dev.js.map +1 -1
  25. package/dist/commands/start.js +2 -2
  26. package/dist/commands/start.js.map +1 -1
  27. package/dist/context-warnings.d.ts +5 -0
  28. package/dist/context-warnings.js +31 -0
  29. package/dist/context-warnings.js.map +1 -0
  30. package/dist/context-warnings.test.js +28 -0
  31. package/dist/context-warnings.test.js.map +1 -0
  32. package/dist/server/app.d.ts +194 -0
  33. package/dist/server/app.js +266 -0
  34. package/dist/server/app.js.map +1 -0
  35. package/dist/server/app.test.js +97 -0
  36. package/dist/server/app.test.js.map +1 -0
  37. package/dist/server/auth/discovery.d.ts +2 -1
  38. package/dist/server/auth/discovery.js +2 -2
  39. package/dist/server/auth/discovery.js.map +1 -1
  40. package/dist/server/auth/index.d.ts +35 -5
  41. package/dist/server/auth/index.js.map +1 -1
  42. package/dist/server/auth/providers/auth0.d.ts +25 -3
  43. package/dist/server/auth/providers/auth0.js +13 -8
  44. package/dist/server/auth/providers/auth0.js.map +1 -1
  45. package/dist/server/auth/providers/auth0.test.js +5 -3
  46. package/dist/server/auth/providers/auth0.test.js.map +1 -1
  47. package/dist/server/auth/providers/authplane.d.ts +49 -0
  48. package/dist/server/auth/providers/authplane.js +57 -0
  49. package/dist/server/auth/providers/authplane.js.map +1 -0
  50. package/dist/server/auth/providers/authplane.test.js +143 -0
  51. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  52. package/dist/server/auth/providers/clerk.d.ts +40 -3
  53. package/dist/server/auth/providers/clerk.js +4 -1
  54. package/dist/server/auth/providers/clerk.js.map +1 -1
  55. package/dist/server/auth/providers/clerk.test.js +5 -3
  56. package/dist/server/auth/providers/clerk.test.js.map +1 -1
  57. package/dist/server/auth/providers/custom.d.ts +21 -9
  58. package/dist/server/auth/providers/custom.js +29 -10
  59. package/dist/server/auth/providers/custom.js.map +1 -1
  60. package/dist/server/auth/providers/custom.test.js +57 -24
  61. package/dist/server/auth/providers/custom.test.js.map +1 -1
  62. package/dist/server/auth/providers/descope.d.ts +32 -3
  63. package/dist/server/auth/providers/descope.js +12 -3
  64. package/dist/server/auth/providers/descope.js.map +1 -1
  65. package/dist/server/auth/providers/descope.test.js +42 -19
  66. package/dist/server/auth/providers/descope.test.js.map +1 -1
  67. package/dist/server/auth/providers/stytch.d.ts +16 -3
  68. package/dist/server/auth/providers/stytch.js +4 -1
  69. package/dist/server/auth/providers/stytch.js.map +1 -1
  70. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  71. package/dist/server/auth/providers/verify-spy.js +21 -0
  72. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  73. package/dist/server/auth/providers/workos.d.ts +28 -5
  74. package/dist/server/auth/providers/workos.js +6 -2
  75. package/dist/server/auth/providers/workos.js.map +1 -1
  76. package/dist/server/auth/setup.d.ts +1 -1
  77. package/dist/server/auth/setup.js +4 -5
  78. package/dist/server/auth/setup.js.map +1 -1
  79. package/dist/server/auth/setup.test.js +97 -57
  80. package/dist/server/auth/setup.test.js.map +1 -1
  81. package/dist/server/auth/verify.d.ts +42 -6
  82. package/dist/server/auth/verify.js +27 -3
  83. package/dist/server/auth/verify.js.map +1 -1
  84. package/dist/server/auth/verify.test.js +65 -0
  85. package/dist/server/auth/verify.test.js.map +1 -1
  86. package/dist/server/auth-extra.test-d.js +130 -0
  87. package/dist/server/auth-extra.test-d.js.map +1 -0
  88. package/dist/server/auth.d.ts +43 -6
  89. package/dist/server/auth.js +4 -5
  90. package/dist/server/auth.js.map +1 -1
  91. package/dist/server/build-manifest.test.js +7 -6
  92. package/dist/server/build-manifest.test.js.map +1 -1
  93. package/dist/server/content-helpers.d.ts +1 -1
  94. package/dist/server/content-helpers.js.map +1 -1
  95. package/dist/server/express.d.ts +23 -3
  96. package/dist/server/express.js +38 -32
  97. package/dist/server/express.js.map +1 -1
  98. package/dist/server/express.test.js +220 -103
  99. package/dist/server/express.test.js.map +1 -1
  100. package/dist/server/file-ref.d.ts +1 -1
  101. package/dist/server/file-ref.js +1 -1
  102. package/dist/server/file-ref.js.map +1 -1
  103. package/dist/server/form-input.d.ts +120 -0
  104. package/dist/server/form-input.js +89 -0
  105. package/dist/server/form-input.js.map +1 -0
  106. package/dist/server/index.d.ts +15 -8
  107. package/dist/server/index.js +8 -2
  108. package/dist/server/index.js.map +1 -1
  109. package/dist/server/mcp-errors.test.js +41 -0
  110. package/dist/server/mcp-errors.test.js.map +1 -0
  111. package/dist/server/middleware.d.ts +35 -10
  112. package/dist/server/middleware.js +33 -0
  113. package/dist/server/middleware.js.map +1 -1
  114. package/dist/server/middleware.test-d.js +1 -1
  115. package/dist/server/middleware.test-d.js.map +1 -1
  116. package/dist/server/middleware.test.js +242 -134
  117. package/dist/server/middleware.test.js.map +1 -1
  118. package/dist/server/register-tool.test.js +230 -0
  119. package/dist/server/register-tool.test.js.map +1 -0
  120. package/dist/server/server.d.ts +306 -128
  121. package/dist/server/server.js +335 -305
  122. package/dist/server/server.js.map +1 -1
  123. package/dist/server/skills-integration.test.js +19 -12
  124. package/dist/server/skills-integration.test.js.map +1 -1
  125. package/dist/server/skills.d.ts +3 -5
  126. package/dist/server/skills.js +17 -24
  127. package/dist/server/skills.js.map +1 -1
  128. package/dist/server/skills.test.js +8 -12
  129. package/dist/server/skills.test.js.map +1 -1
  130. package/dist/server/templateHelper.d.ts +0 -3
  131. package/dist/server/templateHelper.js.map +1 -1
  132. package/dist/server/templates.generated.js +4 -8
  133. package/dist/server/templates.generated.js.map +1 -1
  134. package/dist/server/tool-extra.test.js +167 -0
  135. package/dist/server/tool-extra.test.js.map +1 -0
  136. package/dist/server/view-resource-resolution.test.js +18 -13
  137. package/dist/server/view-resource-resolution.test.js.map +1 -1
  138. package/dist/test/utils.d.ts +9 -11
  139. package/dist/test/utils.js +220 -201
  140. package/dist/test/utils.js.map +1 -1
  141. package/dist/test/view.test.js +41 -37
  142. package/dist/test/view.test.js.map +1 -1
  143. package/dist/views/index.d.ts +10 -0
  144. package/dist/views/index.js +3 -0
  145. package/dist/views/index.js.map +1 -0
  146. package/dist/{web/plugin → views}/scan-views.js +1 -1
  147. package/dist/views/scan-views.js.map +1 -0
  148. package/dist/views/scan-views.test.d.ts +1 -0
  149. package/dist/views/scan-views.test.js.map +1 -0
  150. package/dist/views/validate-view.d.ts +1 -0
  151. package/dist/{web/plugin → views}/validate-view.js +2 -2
  152. package/dist/views/validate-view.js.map +1 -0
  153. package/dist/views/validate-view.test.d.ts +1 -0
  154. package/dist/views/validate-view.test.js.map +1 -0
  155. package/dist/web/bridges/adaptor.d.ts +14 -3
  156. package/dist/web/bridges/adaptor.js +158 -28
  157. package/dist/web/bridges/adaptor.js.map +1 -1
  158. package/dist/web/bridges/adaptor.test.js +49 -9
  159. package/dist/web/bridges/adaptor.test.js.map +1 -1
  160. package/dist/web/bridges/apps-sdk/bridge.js +1 -1
  161. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  162. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +4 -4
  163. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +4 -4
  164. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  165. package/dist/web/bridges/get-adaptor.test.js +2 -2
  166. package/dist/web/bridges/get-adaptor.test.js.map +1 -1
  167. package/dist/web/bridges/mcp-app/bridge.d.ts +1 -1
  168. package/dist/web/bridges/mcp-app/bridge.js +15 -6
  169. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  170. package/dist/web/bridges/mcp-app/bridge.test.js +2 -2
  171. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -1
  172. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  173. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  174. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
  175. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  176. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  177. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  178. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  179. package/dist/web/bridges/mcp-app/view-tools.test.js +1 -1
  180. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  181. package/dist/web/bridges/types.d.ts +74 -16
  182. package/dist/web/bridges/types.js +1 -1
  183. package/dist/web/bridges/types.js.map +1 -1
  184. package/dist/web/create-store.test.js +2 -2
  185. package/dist/web/create-store.test.js.map +1 -1
  186. package/dist/web/data-llm.js +3 -2
  187. package/dist/web/data-llm.js.map +1 -1
  188. package/dist/web/data-llm.test.js +11 -4
  189. package/dist/web/data-llm.test.js.map +1 -1
  190. package/dist/web/generate-helpers.d.ts +23 -19
  191. package/dist/web/generate-helpers.js +21 -17
  192. package/dist/web/generate-helpers.js.map +1 -1
  193. package/dist/web/generate-helpers.test-d.js +3 -3
  194. package/dist/web/generate-helpers.test-d.js.map +1 -1
  195. package/dist/web/generate-helpers.test.js +2 -2
  196. package/dist/web/generate-helpers.test.js.map +1 -1
  197. package/dist/web/hooks/index.d.ts +6 -1
  198. package/dist/web/hooks/index.js +6 -1
  199. package/dist/web/hooks/index.js.map +1 -1
  200. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  201. package/dist/web/hooks/openai-extensions.test.js +107 -0
  202. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  203. package/dist/web/hooks/test/utils.d.ts +2 -1
  204. package/dist/web/hooks/test/utils.js +1 -1
  205. package/dist/web/hooks/test/utils.js.map +1 -1
  206. package/dist/web/hooks/use-call-tool.d.ts +2 -2
  207. package/dist/web/hooks/use-call-tool.js +15 -10
  208. package/dist/web/hooks/use-call-tool.js.map +1 -1
  209. package/dist/web/hooks/use-call-tool.test.js +15 -4
  210. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  211. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  212. package/dist/web/hooks/use-deep-link.js +34 -0
  213. package/dist/web/hooks/use-deep-link.js.map +1 -0
  214. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  215. package/dist/web/hooks/use-display-mode.js +1 -1
  216. package/dist/web/hooks/use-display-mode.js.map +1 -1
  217. package/dist/web/hooks/use-display-mode.test.js +1 -1
  218. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  219. package/dist/web/hooks/use-download.d.ts +1 -3
  220. package/dist/web/hooks/use-download.js +1 -2
  221. package/dist/web/hooks/use-download.js.map +1 -1
  222. package/dist/web/hooks/use-download.test.js +7 -7
  223. package/dist/web/hooks/use-download.test.js.map +1 -1
  224. package/dist/web/hooks/use-file-resource.d.ts +37 -0
  225. package/dist/web/hooks/use-file-resource.js +98 -0
  226. package/dist/web/hooks/use-file-resource.js.map +1 -0
  227. package/dist/web/hooks/use-file-resource.test.d.ts +1 -0
  228. package/dist/web/hooks/use-file-resource.test.js +65 -0
  229. package/dist/web/hooks/use-file-resource.test.js.map +1 -0
  230. package/dist/web/hooks/use-files.test.js +1 -1
  231. package/dist/web/hooks/use-files.test.js.map +1 -1
  232. package/dist/web/hooks/use-host.d.ts +44 -0
  233. package/dist/web/hooks/use-host.js +45 -0
  234. package/dist/web/hooks/use-host.js.map +1 -0
  235. package/dist/web/hooks/use-host.test.d.ts +1 -0
  236. package/dist/web/hooks/use-host.test.js +59 -0
  237. package/dist/web/hooks/use-host.test.js.map +1 -0
  238. package/dist/web/hooks/use-model-context.d.ts +44 -0
  239. package/dist/web/hooks/use-model-context.js +63 -0
  240. package/dist/web/hooks/use-model-context.js.map +1 -0
  241. package/dist/web/hooks/use-open-external.test.js +2 -2
  242. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  243. package/dist/web/hooks/use-open-file.d.ts +20 -0
  244. package/dist/web/hooks/use-open-file.js +25 -0
  245. package/dist/web/hooks/use-open-file.js.map +1 -0
  246. package/dist/web/hooks/use-register-view-tool.d.ts +3 -4
  247. package/dist/web/hooks/use-register-view-tool.js +1 -1
  248. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  249. package/dist/web/hooks/use-request-close.test.js +1 -1
  250. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  251. package/dist/web/hooks/use-request-modal.test.js +1 -1
  252. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  253. package/dist/web/hooks/use-request-size.d.ts +1 -1
  254. package/dist/web/hooks/use-request-size.js +1 -1
  255. package/dist/web/hooks/use-request-size.js.map +1 -1
  256. package/dist/web/hooks/use-request-size.test.js +1 -1
  257. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  258. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  259. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  260. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  261. package/dist/web/hooks/use-set-open-in-app-url.test.js +2 -8
  262. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  263. package/dist/web/hooks/use-tool-info.d.ts +1 -20
  264. package/dist/web/hooks/use-tool-info.js +0 -1
  265. package/dist/web/hooks/use-tool-info.js.map +1 -1
  266. package/dist/web/hooks/use-tool-info.test-d.js +0 -5
  267. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  268. package/dist/web/hooks/use-tool-info.test.js +2 -7
  269. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  270. package/dist/web/hooks/use-user.d.ts +3 -2
  271. package/dist/web/hooks/use-user.js +4 -3
  272. package/dist/web/hooks/use-user.js.map +1 -1
  273. package/dist/web/hooks/use-user.test.js +5 -3
  274. package/dist/web/hooks/use-user.test.js.map +1 -1
  275. package/dist/web/hooks/use-view-state.js +19 -9
  276. package/dist/web/hooks/use-view-state.js.map +1 -1
  277. package/dist/web/hooks/use-view-state.test.js +33 -2
  278. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  279. package/dist/web/hooks/use-viewport.d.ts +20 -0
  280. package/dist/web/hooks/use-viewport.js +21 -0
  281. package/dist/web/hooks/use-viewport.js.map +1 -0
  282. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  283. package/dist/web/hooks/{use-layout.test.js → use-viewport.test.js} +12 -32
  284. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  285. package/dist/web/mount-view.d.ts +3 -2
  286. package/dist/web/mount-view.js +5 -8
  287. package/dist/web/mount-view.js.map +1 -1
  288. package/package.json +15 -13
  289. package/dist/web/hooks/use-layout.d.ts +0 -24
  290. package/dist/web/hooks/use-layout.js +0 -25
  291. package/dist/web/hooks/use-layout.js.map +0 -1
  292. package/dist/web/hooks/use-layout.test.js.map +0 -1
  293. package/dist/web/plugin/data-llm.test.js +0 -81
  294. package/dist/web/plugin/data-llm.test.js.map +0 -1
  295. package/dist/web/plugin/plugin-build.test.js +0 -54
  296. package/dist/web/plugin/plugin-build.test.js.map +0 -1
  297. package/dist/web/plugin/plugin.d.ts +0 -39
  298. package/dist/web/plugin/plugin.js +0 -200
  299. package/dist/web/plugin/plugin.js.map +0 -1
  300. package/dist/web/plugin/plugin.test.js +0 -61
  301. package/dist/web/plugin/plugin.test.js.map +0 -1
  302. package/dist/web/plugin/scan-views.js.map +0 -1
  303. package/dist/web/plugin/scan-views.test.js.map +0 -1
  304. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  305. package/dist/web/plugin/transform-data-llm.js +0 -96
  306. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  307. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  308. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  309. package/dist/web/plugin/validate-view.d.ts +0 -1
  310. package/dist/web/plugin/validate-view.js.map +0 -1
  311. package/dist/web/plugin/validate-view.test.js.map +0 -1
  312. /package/dist/{web/hooks/use-layout.test.d.ts → context-warnings.test.d.ts} +0 -0
  313. /package/dist/{web/plugin/data-llm.test.d.ts → server/app.test.d.ts} +0 -0
  314. /package/dist/{web/plugin/plugin.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  315. /package/dist/{web/plugin/plugin-build.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  316. /package/dist/{web/plugin/scan-views.test.d.ts → server/mcp-errors.test.d.ts} +0 -0
  317. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/register-tool.test.d.ts} +0 -0
  318. /package/dist/{web/plugin/validate-view.test.d.ts → server/tool-extra.test.d.ts} +0 -0
  319. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  320. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  321. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -1,12 +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
24
  audience: string;
12
- } & Omit<CustomProviderOptions, "issuer" | "audience">): Promise<OAuthConfig>;
25
+ } & Omit<CustomProviderOptions, "issuer" | "audience">): OAuthProvider<StytchClaims & TCustom & RegisteredClaims>;
@@ -8,6 +8,9 @@ import { toIssuerUrl } from "./shared.js";
8
8
  */
9
9
  export function stytchProvider(opts) {
10
10
  const { domain, ...rest } = opts;
11
- return customProvider({ issuer: toIssuerUrl(domain), ...rest });
11
+ return customProvider({
12
+ issuer: toIssuerUrl(domain),
13
+ ...rest,
14
+ });
12
15
  }
13
16
  //# sourceMappingURL=stytch.js.map
@@ -1 +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"]}
1
+ {"version":3,"file":"stytch.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/stytch.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAc1C;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAG5B,IAGC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,cAAc,CAAyB;QAC5C,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;QAC3B,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\";\nimport { toIssuerUrl } from \"./shared.js\";\n\n/**\n * Claims a Stytch Connected Apps access token carries. Beyond the subject,\n * everything is project-configured through the client's access-token template.\n *\n * @see https://stytch.com/docs/api-reference/consumer/api/connected-apps/tokens/connected-app-access-token-object\n * @see https://stytch.com/docs/api/connected-apps-create\n */\nexport type StytchClaims = {\n /** Only when the client's access-token template adds it. */\n email?: string;\n};\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 TCustom extends ExtraClaims = Record<never, never>,\n>(\n opts: { domain: string; audience: string } & Omit<\n CustomProviderOptions,\n \"issuer\" | \"audience\"\n >,\n): OAuthProvider<StytchClaims & TCustom & RegisteredClaims> {\n const { domain, ...rest } = opts;\n return customProvider<StytchClaims & TCustom>({\n issuer: toIssuerUrl(domain),\n ...rest,\n });\n}\n"]}
@@ -0,0 +1,12 @@
1
+ export declare const createJwksVerifier: import("vitest").Mock<typeof import("../verify.js").createJwksVerifier>;
2
+ /**
3
+ * The JWKS parameters a provider handed to `createJwksVerifier`: the issuer and
4
+ * JWKS URL it derived from discovery, and the audience it expects. Substitute
5
+ * this module for `../verify.js` to assert on them:
6
+ *
7
+ * ```ts
8
+ * vi.mock("../verify.js", () => import("./verify-spy.js"));
9
+ * import { lastJwksConfig as jwks } from "./verify-spy.js";
10
+ * ```
11
+ */
12
+ export declare const lastJwksConfig: () => import("../verify.js").JwksVerifyConfig;
@@ -0,0 +1,21 @@
1
+ import { vi } from "vitest";
2
+ const actual = await vi.importActual("../verify.js");
3
+ export const createJwksVerifier = vi.fn(actual.createJwksVerifier);
4
+ /**
5
+ * The JWKS parameters a provider handed to `createJwksVerifier`: the issuer and
6
+ * JWKS URL it derived from discovery, and the audience it expects. Substitute
7
+ * this module for `../verify.js` to assert on them:
8
+ *
9
+ * ```ts
10
+ * vi.mock("../verify.js", () => import("./verify-spy.js"));
11
+ * import { lastJwksConfig as jwks } from "./verify-spy.js";
12
+ * ```
13
+ */
14
+ export const lastJwksConfig = () => {
15
+ const call = createJwksVerifier.mock.lastCall;
16
+ if (!call) {
17
+ throw new Error("createJwksVerifier was not called");
18
+ }
19
+ return call[0];
20
+ };
21
+ //# sourceMappingURL=verify-spy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-spy.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/verify-spy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE5B,MAAM,MAAM,GACV,MAAM,EAAE,CAAC,YAAY,CAAgC,cAAc,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE;IACjC,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC;IAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC","sourcesContent":["import { vi } from \"vitest\";\n\nconst actual =\n await vi.importActual<typeof import(\"../verify.js\")>(\"../verify.js\");\n\nexport const createJwksVerifier = vi.fn(actual.createJwksVerifier);\n\n/**\n * The JWKS parameters a provider handed to `createJwksVerifier`: the issuer and\n * JWKS URL it derived from discovery, and the audience it expects. Substitute\n * this module for `../verify.js` to assert on them:\n *\n * ```ts\n * vi.mock(\"../verify.js\", () => import(\"./verify-spy.js\"));\n * import { lastJwksConfig as jwks } from \"./verify-spy.js\";\n * ```\n */\nexport const lastJwksConfig = () => {\n const call = createJwksVerifier.mock.lastCall;\n if (!call) {\n throw new Error(\"createJwksVerifier was not called\");\n }\n return call[0];\n};\n"]}
@@ -1,11 +1,34 @@
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 WorkOS AuthKit access token carries. All optional: `org_id`, `role`
7
+ * and `permissions` appear only when an organization is selected at sign-in, and
8
+ * `email` only when a JWT template adds it.
9
+ *
10
+ * @see https://workos.com/docs/authkit/sessions/integrating-sessions/access-token
11
+ * @see https://workos.com/docs/authkit/jwt-templates
12
+ */
13
+ export type WorkosClaims = {
14
+ /** Session id, used for signing out. */
15
+ sid?: string;
16
+ /** Organization selected at sign-in. */
17
+ org_id?: string;
18
+ /** Role of the selected organization membership. */
19
+ role?: string;
20
+ /** Permissions assigned to the role. */
21
+ permissions?: string[];
22
+ /** Only when a JWT template adds it; not a default AuthKit claim. */
23
+ email?: string;
24
+ };
3
25
  /**
4
26
  * OAuth provider for WorkOS AuthKit. `domain` is the AuthKit domain, e.g.
5
27
  * `acme.authkit.app`. Requires DCR enabled in the WorkOS dashboard
6
- * (Connect → Configuration). `audience` is the MCP server's Resource Indicator.
28
+ * (Connect → Configuration). `audience` is the MCP server's Resource Indicator,
29
+ * or every Resource Indicator it answers to when it is reached at more than one URL.
7
30
  */
8
- export declare function workosProvider(opts: {
31
+ export declare function workosProvider<TCustom extends ExtraClaims = Record<never, never>>(opts: {
9
32
  domain: string;
10
- audience: string;
11
- } & Omit<CustomProviderOptions, "issuer" | "audience">): Promise<OAuthConfig>;
33
+ audience: string | string[];
34
+ } & Omit<CustomProviderOptions, "issuer" | "audience">): OAuthProvider<WorkosClaims & TCustom & RegisteredClaims>;
@@ -3,10 +3,14 @@ import { toIssuerUrl } from "./shared.js";
3
3
  /**
4
4
  * OAuth provider for WorkOS AuthKit. `domain` is the AuthKit domain, e.g.
5
5
  * `acme.authkit.app`. Requires DCR enabled in the WorkOS dashboard
6
- * (Connect → Configuration). `audience` is the MCP server's Resource Indicator.
6
+ * (Connect → Configuration). `audience` is the MCP server's Resource Indicator,
7
+ * or every Resource Indicator it answers to when it is reached at more than one URL.
7
8
  */
8
9
  export function workosProvider(opts) {
9
10
  const { domain, ...rest } = opts;
10
- return customProvider({ issuer: toIssuerUrl(domain), ...rest });
11
+ return customProvider({
12
+ issuer: toIssuerUrl(domain),
13
+ ...rest,
14
+ });
11
15
  }
12
16
  //# sourceMappingURL=workos.js.map
@@ -1 +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"]}
1
+ {"version":3,"file":"workos.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/workos.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAuB1C;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAG5B,IAGC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,cAAc,CAAyB;QAC5C,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;QAC3B,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\";\nimport { toIssuerUrl } from \"./shared.js\";\n\n/**\n * Claims a WorkOS AuthKit access token carries. All optional: `org_id`, `role`\n * and `permissions` appear only when an organization is selected at sign-in, and\n * `email` only when a JWT template adds it.\n *\n * @see https://workos.com/docs/authkit/sessions/integrating-sessions/access-token\n * @see https://workos.com/docs/authkit/jwt-templates\n */\nexport type WorkosClaims = {\n /** Session id, used for signing out. */\n sid?: string;\n /** Organization selected at sign-in. */\n org_id?: string;\n /** Role of the selected organization membership. */\n role?: string;\n /** Permissions assigned to the role. */\n permissions?: string[];\n /** Only when a JWT template adds it; not a default AuthKit claim. */\n email?: string;\n};\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 * or every Resource Indicator it answers to when it is reached at more than one URL.\n */\nexport function workosProvider<\n TCustom extends ExtraClaims = Record<never, never>,\n>(\n opts: { domain: string; audience: string | string[] } & Omit<\n CustomProviderOptions,\n \"issuer\" | \"audience\"\n >,\n): OAuthProvider<WorkosClaims & TCustom & RegisteredClaims> {\n const { domain, ...rest } = opts;\n return customProvider<WorkosClaims & TCustom>({\n issuer: toIssuerUrl(domain),\n ...rest,\n });\n}\n"]}
@@ -3,4 +3,4 @@ import type { SecurityScheme } from "../server.js";
3
3
  import type { OAuthConfig } from "./index.js";
4
4
  export type ResourceMetadataUrlResolver = (getHeader: (key: string) => string | undefined) => string;
5
5
  /** Mounts the well-known OAuth metadata and bearer auth on `/mcp`. */
6
- export declare function setupOAuth(app: Express, config: OAuthConfig, schemesByTool: Map<string, SecurityScheme[] | undefined>): ResourceMetadataUrlResolver;
6
+ export declare function setupOAuth(app: Express, config: OAuthConfig<Record<string, unknown>>, schemesByTool: ReadonlyMap<string, SecurityScheme[] | undefined>): ResourceMetadataUrlResolver;
@@ -1,16 +1,15 @@
1
- import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter, } from "@modelcontextprotocol/sdk/server/auth/router.js";
1
+ import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter, } from "@modelcontextprotocol/express";
2
2
  import cors from "cors";
3
3
  import { optionalBearerAuth, requireBearerAuth } from "../auth.js";
4
4
  import { resolveServerOrigin } from "../requestOrigin.js";
5
5
  import { clientPrefersInBandChallenge, evaluateSecuritySchemes, httpStatusForFailure, inBandChallengeResult, securitySchemesAllowAnonymous, wwwAuthenticateHeader, } from "./security-schemes.js";
6
- import { createJwksVerifier } from "./verify.js";
7
6
  /** Mounts the well-known OAuth metadata and bearer auth on `/mcp`. */
8
7
  export function setupOAuth(app, config, schemesByTool) {
9
- if (!config.verify?.issuer) {
10
- throw new Error("oauth.verify requires an `issuer`");
8
+ if (!config.verifier) {
9
+ throw new Error("oauth requires a `verifier`");
11
10
  }
12
11
  const acceptsAnonymous = () => [...schemesByTool.values()].some(securitySchemesAllowAnonymous);
13
- const verifier = createJwksVerifier(config.verify);
12
+ const verifier = config.verifier;
14
13
  const bearer = (options) => {
15
14
  const required = requireBearerAuth(options);
16
15
  const optional = optionalBearerAuth(options);
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/server/auth/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BearerAuthMiddlewareOptions } from \"@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js\";\nimport {\n getOAuthProtectedResourceMetadataUrl,\n mcpAuthMetadataRouter,\n} from \"@modelcontextprotocol/sdk/server/auth/router.js\";\nimport cors from \"cors\";\nimport type { Express, Request, RequestHandler } from \"express\";\nimport type { AuthInfo } from \"../auth.js\";\nimport { optionalBearerAuth, requireBearerAuth } from \"../auth.js\";\nimport { resolveServerOrigin } from \"../requestOrigin.js\";\nimport type { SecurityScheme } from \"../server.js\";\nimport type { OAuthConfig } from \"./index.js\";\nimport {\n clientPrefersInBandChallenge,\n evaluateSecuritySchemes,\n httpStatusForFailure,\n inBandChallengeResult,\n type SchemeFailure,\n securitySchemesAllowAnonymous,\n wwwAuthenticateHeader,\n} from \"./security-schemes.js\";\nimport { createJwksVerifier } from \"./verify.js\";\n\nexport type ResourceMetadataUrlResolver = (\n getHeader: (key: string) => string | undefined,\n) => string;\n\n/** Mounts the well-known OAuth metadata and bearer auth on `/mcp`. */\nexport function setupOAuth(\n app: Express,\n config: OAuthConfig,\n schemesByTool: Map<string, SecurityScheme[] | undefined>,\n): ResourceMetadataUrlResolver {\n if (!config.verify?.issuer) {\n throw new Error(\"oauth.verify requires an `issuer`\");\n }\n\n const acceptsAnonymous = () =>\n [...schemesByTool.values()].some(securitySchemesAllowAnonymous);\n const verifier = createJwksVerifier(config.verify);\n const bearer = (options: BearerAuthMiddlewareOptions): RequestHandler => {\n const required = requireBearerAuth(options);\n const optional = optionalBearerAuth(options);\n return (req, res, next) =>\n (acceptsAnonymous() ? optional : required)(req, res, next);\n };\n\n let resourceMetadataUrl: ResourceMetadataUrlResolver;\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 const url = getOAuthProtectedResourceMetadataUrl(baseUrl);\n resourceMetadataUrl = () => url;\n } else {\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 = (getHeader: (key: string) => string | undefined) =>\n new URL(resolveServerOrigin(getHeader));\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((key) => req.get(key)).href,\n authorization_servers: [config.oauthMetadata.issuer],\n scopes_supported: config.scopesSupported,\n });\n });\n resourceMetadataUrl = (getHeader) =>\n getOAuthProtectedResourceMetadataUrl(resolveOrigin(getHeader));\n }\n\n app.use(\"/mcp\", (req, res, next) =>\n bearer({\n verifier,\n requiredScopes: config.requiredScopes,\n resourceMetadataUrl: resourceMetadataUrl((key) => req.get(key)),\n })(req, res, next),\n );\n\n app.use(\"/mcp\", (req, res, next) => {\n type Call = {\n id?: string | number | null;\n method?: string;\n params?: { name?: string };\n };\n const body = req.body as Call | Call[] | undefined;\n const calls = Array.isArray(body) ? body : [body];\n const auth = (req as Request & { auth?: AuthInfo }).auth;\n let failure: SchemeFailure | undefined;\n for (const call of calls) {\n const tool = call?.params?.name;\n if (call?.method === \"tools/call\" && tool && schemesByTool.has(tool)) {\n failure = evaluateSecuritySchemes(schemesByTool.get(tool), auth);\n if (failure) {\n break;\n }\n }\n }\n if (!failure) {\n return next();\n }\n const url = resourceMetadataUrl((key) => req.get(key));\n if (\n !Array.isArray(body) &&\n clientPrefersInBandChallenge(req.get(\"user-agent\"))\n ) {\n res.json({\n jsonrpc: \"2.0\",\n id: body?.id ?? null,\n result: inBandChallengeResult(failure, url),\n });\n return;\n }\n res.set(\"WWW-Authenticate\", wwwAuthenticateHeader(failure, url));\n res.status(httpStatusForFailure(failure)).json({\n error: failure.error,\n error_description: failure.description,\n });\n });\n\n return resourceMetadataUrl;\n}\n"]}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/server/auth/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type BearerAuthMiddlewareOptions,\n getOAuthProtectedResourceMetadataUrl,\n mcpAuthMetadataRouter,\n} from \"@modelcontextprotocol/express\";\nimport cors from \"cors\";\nimport type { Express, Request, RequestHandler } from \"express\";\nimport type { AuthInfo } from \"../auth.js\";\nimport { optionalBearerAuth, requireBearerAuth } from \"../auth.js\";\nimport { resolveServerOrigin } from \"../requestOrigin.js\";\nimport type { SecurityScheme } from \"../server.js\";\nimport type { OAuthConfig } from \"./index.js\";\nimport {\n clientPrefersInBandChallenge,\n evaluateSecuritySchemes,\n httpStatusForFailure,\n inBandChallengeResult,\n type SchemeFailure,\n securitySchemesAllowAnonymous,\n wwwAuthenticateHeader,\n} from \"./security-schemes.js\";\n\nexport type ResourceMetadataUrlResolver = (\n getHeader: (key: string) => string | undefined,\n) => string;\n\n/** Mounts the well-known OAuth metadata and bearer auth on `/mcp`. */\nexport function setupOAuth(\n app: Express,\n config: OAuthConfig<Record<string, unknown>>,\n schemesByTool: ReadonlyMap<string, SecurityScheme[] | undefined>,\n): ResourceMetadataUrlResolver {\n if (!config.verifier) {\n throw new Error(\"oauth requires a `verifier`\");\n }\n\n const acceptsAnonymous = () =>\n [...schemesByTool.values()].some(securitySchemesAllowAnonymous);\n const verifier = config.verifier;\n const bearer = (options: BearerAuthMiddlewareOptions): RequestHandler => {\n const required = requireBearerAuth(options);\n const optional = optionalBearerAuth(options);\n return (req, res, next) =>\n (acceptsAnonymous() ? optional : required)(req, res, next);\n };\n\n let resourceMetadataUrl: ResourceMetadataUrlResolver;\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 const url = getOAuthProtectedResourceMetadataUrl(baseUrl);\n resourceMetadataUrl = () => url;\n } else {\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 = (getHeader: (key: string) => string | undefined) =>\n new URL(resolveServerOrigin(getHeader));\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((key) => req.get(key)).href,\n authorization_servers: [config.oauthMetadata.issuer],\n scopes_supported: config.scopesSupported,\n });\n });\n resourceMetadataUrl = (getHeader) =>\n getOAuthProtectedResourceMetadataUrl(resolveOrigin(getHeader));\n }\n\n app.use(\"/mcp\", (req, res, next) =>\n bearer({\n verifier,\n requiredScopes: config.requiredScopes,\n resourceMetadataUrl: resourceMetadataUrl((key) => req.get(key)),\n })(req, res, next),\n );\n\n app.use(\"/mcp\", (req, res, next) => {\n type Call = {\n id?: string | number | null;\n method?: string;\n params?: { name?: string };\n };\n const body = req.body as Call | Call[] | undefined;\n const calls = Array.isArray(body) ? body : [body];\n const auth = (req as Request & { auth?: AuthInfo }).auth;\n let failure: SchemeFailure | undefined;\n for (const call of calls) {\n const tool = call?.params?.name;\n if (call?.method === \"tools/call\" && tool && schemesByTool.has(tool)) {\n failure = evaluateSecuritySchemes(schemesByTool.get(tool), auth);\n if (failure) {\n break;\n }\n }\n }\n if (!failure) {\n return next();\n }\n const url = resourceMetadataUrl((key) => req.get(key));\n if (\n !Array.isArray(body) &&\n clientPrefersInBandChallenge(req.get(\"user-agent\"))\n ) {\n res.json({\n jsonrpc: \"2.0\",\n id: body?.id ?? null,\n result: inBandChallengeResult(failure, url),\n });\n return;\n }\n res.set(\"WWW-Authenticate\", wwwAuthenticateHeader(failure, url));\n res.status(httpStatusForFailure(failure)).json({\n error: failure.error,\n error_description: failure.description,\n });\n });\n\n return resourceMetadataUrl;\n}\n"]}
@@ -1,10 +1,11 @@
1
1
  // @vitest-environment node
2
2
  import http from "node:http";
3
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ import { Client, StreamableHTTPClientTransport, } from "@modelcontextprotocol/client";
5
4
  import * as jose from "jose";
6
5
  import { afterEach, describe, expect, it, vi } from "vitest";
6
+ import { Skybridge } from "../app.js";
7
7
  import { McpServer } from "../server.js";
8
+ import { createJwksVerifier } from "./verify.js";
8
9
  vi.mock("@skybridge/devtools", () => ({
9
10
  devtoolsStaticServer: () => ((_req, _res, next) => next()),
10
11
  }));
@@ -50,7 +51,9 @@ function signToken(key, scope = "openid email") {
50
51
  }
51
52
  async function bootServer(jwksUri, { baseUrl = "https://app.example.test" } = {}) {
52
53
  const { createApp } = await import("../express.js");
53
- const server = new McpServer({ name: "auth-test", version: "0.0.0" }, { capabilities: {} }, {
54
+ const app = new Skybridge({
55
+ name: "auth-test",
56
+ version: "0.0.0",
54
57
  oauth: {
55
58
  ...(baseUrl === null ? {} : { baseUrl }),
56
59
  oauthMetadata: {
@@ -59,21 +62,30 @@ async function bootServer(jwksUri, { baseUrl = "https://app.example.test" } = {}
59
62
  token_endpoint: `${ISSUER}/token`,
60
63
  response_types_supported: ["code"],
61
64
  },
62
- verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },
65
+ verifier: createJwksVerifier({
66
+ issuer: ISSUER,
67
+ audience: AUDIENCE,
68
+ jwksUri,
69
+ }),
63
70
  scopesSupported: ["openid", "email"],
64
71
  requiredScopes: ["openid"],
65
72
  },
66
- }).registerTool({
67
- name: "whoami",
68
- description: "Returns the caller identity.",
69
- inputSchema: {},
70
- }, (_args, extra) => ({
71
- structuredContent: { clientId: extra.authInfo?.clientId ?? null },
72
- content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
73
- }));
73
+ handler: (server) => server.registerTool({
74
+ name: "whoami",
75
+ description: "Returns the caller identity.",
76
+ inputSchema: {},
77
+ }, (_args, extra) => ({
78
+ structuredContent: {
79
+ clientId: extra.http?.authInfo?.clientId ?? null,
80
+ },
81
+ content: [
82
+ { type: "text", text: extra.http?.authInfo?.clientId ?? "anon" },
83
+ ],
84
+ })),
85
+ });
74
86
  const httpServer = http.createServer();
75
- await createApp({ mcpServer: server, httpServer });
76
- const listening = http.createServer(server.express);
87
+ await createApp({ app, httpServer });
88
+ const listening = http.createServer(app.express);
77
89
  await new Promise((resolve) => listening.listen(0, resolve));
78
90
  appServer = listening;
79
91
  const port = listening.address().port;
@@ -167,7 +179,9 @@ describe("baseUrl inferred from headers", () => {
167
179
  });
168
180
  async function bootMixedServer(jwksUri) {
169
181
  const { createApp } = await import("../express.js");
170
- const server = new McpServer({ name: "mixed-auth-test", version: "0.0.0" }, { capabilities: {} }, {
182
+ const app = new Skybridge({
183
+ name: "mixed-auth-test",
184
+ version: "0.0.0",
171
185
  oauth: {
172
186
  baseUrl: "https://app.example.test",
173
187
  oauthMetadata: {
@@ -176,34 +190,46 @@ async function bootMixedServer(jwksUri) {
176
190
  token_endpoint: `${ISSUER}/token`,
177
191
  response_types_supported: ["code"],
178
192
  },
179
- verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },
193
+ verifier: createJwksVerifier({
194
+ issuer: ISSUER,
195
+ audience: AUDIENCE,
196
+ jwksUri,
197
+ }),
180
198
  },
181
- })
182
- .registerTool({
183
- name: "public-whoami",
184
- description: "Public.",
185
- inputSchema: {},
186
- auth: { allowsAnonymous: true },
187
- }, (_args, extra) => ({
188
- content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
189
- }))
190
- .registerTool({
191
- name: "private-whoami",
192
- description: "Private.",
193
- inputSchema: {},
194
- auth: {},
195
- }, (_args, extra) => ({
196
- content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
197
- }));
198
- server.registerTool("legacy-whoami", {
199
- description: "Registered via the legacy string overload.",
200
- inputSchema: {},
201
- }, (_args, extra) => ({
202
- content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
203
- }));
199
+ handler: (server) => server
200
+ .registerTool({
201
+ name: "public-whoami",
202
+ description: "Public.",
203
+ inputSchema: {},
204
+ auth: { allowsAnonymous: true },
205
+ }, (_args, extra) => ({
206
+ content: [
207
+ { type: "text", text: extra.http?.authInfo?.clientId ?? "anon" },
208
+ ],
209
+ }))
210
+ .registerTool({
211
+ name: "private-whoami",
212
+ description: "Private.",
213
+ inputSchema: {},
214
+ auth: {},
215
+ }, (_args, extra) => ({
216
+ content: [
217
+ { type: "text", text: extra.http?.authInfo?.clientId ?? "anon" },
218
+ ],
219
+ }))
220
+ .registerTool({
221
+ name: "undeclared-whoami",
222
+ description: "Registered without auth or securitySchemes.",
223
+ inputSchema: {},
224
+ }, (_args, extra) => ({
225
+ content: [
226
+ { type: "text", text: extra.http?.authInfo?.clientId ?? "anon" },
227
+ ],
228
+ })),
229
+ });
204
230
  const httpServer = http.createServer();
205
- await createApp({ mcpServer: server, httpServer });
206
- const listening = http.createServer(server.express);
231
+ await createApp({ app, httpServer });
232
+ const listening = http.createServer(app.express);
207
233
  await new Promise((resolve) => listening.listen(0, resolve));
208
234
  appServer = listening;
209
235
  const port = listening.address().port;
@@ -278,7 +304,7 @@ describe("mixed-auth door", () => {
278
304
  const text = await res.text();
279
305
  expect(text).not.toContain("client-1");
280
306
  });
281
- it("gates a tool registered via the legacy string overload (secure default)", async () => {
307
+ it("gates a tool with no declared schemes (secure default)", async () => {
282
308
  const { jwksUri } = await startJwks();
283
309
  const base = await bootMixedServer(jwksUri);
284
310
  const res = await fetch(`${base}/mcp`, {
@@ -291,7 +317,7 @@ describe("mixed-auth door", () => {
291
317
  jsonrpc: "2.0",
292
318
  id: 1,
293
319
  method: "tools/call",
294
- params: { name: "legacy-whoami", arguments: {} },
320
+ params: { name: "undeclared-whoami", arguments: {} },
295
321
  }),
296
322
  });
297
323
  expect(res.status).toBe(401);
@@ -370,7 +396,9 @@ describe("mixed-auth door", () => {
370
396
  });
371
397
  async function bootScopedServer(jwksUri) {
372
398
  const { createApp } = await import("../express.js");
373
- const server = new McpServer({ name: "scoped-auth-test", version: "0.0.0" }, { capabilities: {} }, {
399
+ const app = new Skybridge({
400
+ name: "scoped-auth-test",
401
+ version: "0.0.0",
374
402
  oauth: {
375
403
  baseUrl: "https://app.example.test",
376
404
  oauthMetadata: {
@@ -379,17 +407,22 @@ async function bootScopedServer(jwksUri) {
379
407
  token_endpoint: `${ISSUER}/token`,
380
408
  response_types_supported: ["code"],
381
409
  },
382
- verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },
410
+ verifier: createJwksVerifier({
411
+ issuer: ISSUER,
412
+ audience: AUDIENCE,
413
+ jwksUri,
414
+ }),
383
415
  },
384
- }).registerTool({
385
- name: "checkout",
386
- description: "Needs the checkout scope.",
387
- inputSchema: {},
388
- auth: { scopes: ["checkout"] },
389
- }, () => ({ content: [{ type: "text", text: "ok" }] }));
416
+ handler: (server) => server.registerTool({
417
+ name: "checkout",
418
+ description: "Needs the checkout scope.",
419
+ inputSchema: {},
420
+ auth: { scopes: ["checkout"] },
421
+ }, () => ({ content: [{ type: "text", text: "ok" }] })),
422
+ });
390
423
  const httpServer = http.createServer();
391
- await createApp({ mcpServer: server, httpServer });
392
- const listening = http.createServer(server.express);
424
+ await createApp({ app, httpServer });
425
+ const listening = http.createServer(app.express);
393
426
  await new Promise((resolve) => listening.listen(0, resolve));
394
427
  appServer = listening;
395
428
  const port = listening.address().port;
@@ -461,14 +494,21 @@ describe("oauth config validation", () => {
461
494
  token_endpoint: `${ISSUER}/token`,
462
495
  response_types_supported: ["code"],
463
496
  };
464
- it("throws on a non-absolute baseUrl", () => {
465
- expect(() => new McpServer({ name: "t", version: "0" }, undefined, {
497
+ it("rejects a non-absolute baseUrl when the app is first used", async () => {
498
+ const app = new Skybridge({
499
+ name: "t",
500
+ version: "0",
466
501
  oauth: {
467
502
  baseUrl: "not-a-url",
468
503
  oauthMetadata: validMetadata,
469
- verify: { issuer: ISSUER, audience: AUDIENCE },
504
+ verifier: createJwksVerifier({
505
+ issuer: ISSUER,
506
+ audience: AUDIENCE,
507
+ }),
470
508
  },
471
- })).toThrow(/baseUrl must be a valid absolute URL/);
509
+ handler: (server) => server,
510
+ });
511
+ await expect(app.createServerInstance()).rejects.toThrow(/baseUrl must be a valid absolute URL/);
472
512
  });
473
513
  });
474
514
  //# sourceMappingURL=setup.test.js.map