skybridge 0.0.0-dev.88e5e83 → 0.0.0-dev.88f1889

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 (360) hide show
  1. package/README.md +17 -23
  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 +194 -0
  44. package/dist/server/app.js +266 -0
  45. package/dist/server/app.js.map +1 -0
  46. package/dist/server/app.test.js +97 -0
  47. package/dist/server/app.test.js.map +1 -0
  48. package/dist/server/auth/discovery.d.ts +2 -1
  49. package/dist/server/auth/discovery.js +2 -2
  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 +25 -3
  54. package/dist/server/auth/providers/auth0.js +13 -8
  55. package/dist/server/auth/providers/auth0.js.map +1 -1
  56. package/dist/server/auth/providers/auth0.test.js +5 -3
  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 +40 -3
  64. package/dist/server/auth/providers/clerk.js +4 -1
  65. package/dist/server/auth/providers/clerk.js.map +1 -1
  66. package/dist/server/auth/providers/clerk.test.js +5 -3
  67. package/dist/server/auth/providers/clerk.test.js.map +1 -1
  68. package/dist/server/auth/providers/custom.d.ts +24 -6
  69. package/dist/server/auth/providers/custom.js +33 -11
  70. package/dist/server/auth/providers/custom.js.map +1 -1
  71. package/dist/server/auth/providers/custom.test.js +71 -17
  72. package/dist/server/auth/providers/custom.test.js.map +1 -1
  73. package/dist/server/auth/providers/descope.d.ts +32 -3
  74. package/dist/server/auth/providers/descope.js +13 -2
  75. package/dist/server/auth/providers/descope.js.map +1 -1
  76. package/dist/server/auth/providers/descope.test.js +42 -17
  77. package/dist/server/auth/providers/descope.test.js.map +1 -1
  78. package/dist/server/auth/providers/stytch.d.ts +16 -3
  79. package/dist/server/auth/providers/stytch.js +4 -1
  80. package/dist/server/auth/providers/stytch.js.map +1 -1
  81. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  82. package/dist/server/auth/providers/verify-spy.js +21 -0
  83. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  84. package/dist/server/auth/providers/workos.d.ts +28 -5
  85. package/dist/server/auth/providers/workos.js +6 -2
  86. package/dist/server/auth/providers/workos.js.map +1 -1
  87. package/dist/server/auth/security-schemes.d.ts +23 -0
  88. package/dist/server/auth/security-schemes.js +64 -0
  89. package/dist/server/auth/security-schemes.js.map +1 -0
  90. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  91. package/dist/server/auth/security-schemes.test.js +99 -0
  92. package/dist/server/auth/security-schemes.test.js.map +1 -0
  93. package/dist/server/auth/setup.d.ts +3 -1
  94. package/dist/server/auth/setup.js +66 -26
  95. package/dist/server/auth/setup.js.map +1 -1
  96. package/dist/server/auth/setup.test.js +349 -20
  97. package/dist/server/auth/setup.test.js.map +1 -1
  98. package/dist/server/auth/verify.d.ts +42 -6
  99. package/dist/server/auth/verify.js +27 -3
  100. package/dist/server/auth/verify.js.map +1 -1
  101. package/dist/server/auth/verify.test.js +65 -0
  102. package/dist/server/auth/verify.test.js.map +1 -1
  103. package/dist/server/auth-extra.test-d.js +130 -0
  104. package/dist/server/auth-extra.test-d.js.map +1 -0
  105. package/dist/server/auth.d.ts +43 -6
  106. package/dist/server/auth.js +4 -5
  107. package/dist/server/auth.js.map +1 -1
  108. package/dist/server/build-manifest.test.js +7 -6
  109. package/dist/server/build-manifest.test.js.map +1 -1
  110. package/dist/server/content-helpers.d.ts +1 -1
  111. package/dist/server/content-helpers.js.map +1 -1
  112. package/dist/server/events.d.ts +113 -0
  113. package/dist/server/events.js +318 -0
  114. package/dist/server/events.js.map +1 -0
  115. package/dist/server/events.test.d.ts +1 -0
  116. package/dist/server/events.test.js +172 -0
  117. package/dist/server/events.test.js.map +1 -0
  118. package/dist/server/express.d.ts +23 -3
  119. package/dist/server/express.js +43 -32
  120. package/dist/server/express.js.map +1 -1
  121. package/dist/server/express.test.js +221 -103
  122. package/dist/server/express.test.js.map +1 -1
  123. package/dist/server/file-ref.d.ts +1 -1
  124. package/dist/server/file-ref.js +1 -1
  125. package/dist/server/file-ref.js.map +1 -1
  126. package/dist/server/form-input.d.ts +120 -0
  127. package/dist/server/form-input.js +89 -0
  128. package/dist/server/form-input.js.map +1 -0
  129. package/dist/server/host.d.ts +2 -0
  130. package/dist/server/host.js +11 -0
  131. package/dist/server/host.js.map +1 -0
  132. package/dist/server/host.test.d.ts +1 -0
  133. package/dist/server/host.test.js +13 -0
  134. package/dist/server/host.test.js.map +1 -0
  135. package/dist/server/index.d.ts +18 -9
  136. package/dist/server/index.js +11 -3
  137. package/dist/server/index.js.map +1 -1
  138. package/dist/server/mcp-errors.test.d.ts +1 -0
  139. package/dist/server/mcp-errors.test.js +41 -0
  140. package/dist/server/mcp-errors.test.js.map +1 -0
  141. package/dist/server/middleware.d.ts +35 -10
  142. package/dist/server/middleware.js +33 -0
  143. package/dist/server/middleware.js.map +1 -1
  144. package/dist/server/middleware.test-d.js +1 -1
  145. package/dist/server/middleware.test-d.js.map +1 -1
  146. package/dist/server/middleware.test.js +242 -134
  147. package/dist/server/middleware.test.js.map +1 -1
  148. package/dist/server/register-tool.test.d.ts +1 -0
  149. package/dist/server/register-tool.test.js +230 -0
  150. package/dist/server/register-tool.test.js.map +1 -0
  151. package/dist/server/server.d.ts +382 -129
  152. package/dist/server/server.js +468 -277
  153. package/dist/server/server.js.map +1 -1
  154. package/dist/server/skills-integration.test.d.ts +1 -0
  155. package/dist/server/skills-integration.test.js +86 -0
  156. package/dist/server/skills-integration.test.js.map +1 -0
  157. package/dist/server/skills.d.ts +27 -0
  158. package/dist/server/skills.js +188 -0
  159. package/dist/server/skills.js.map +1 -0
  160. package/dist/server/skills.test.d.ts +1 -0
  161. package/dist/server/skills.test.js +243 -0
  162. package/dist/server/skills.test.js.map +1 -0
  163. package/dist/server/templateHelper.d.ts +0 -3
  164. package/dist/server/templateHelper.js.map +1 -1
  165. package/dist/server/templates.generated.js +4 -8
  166. package/dist/server/templates.generated.js.map +1 -1
  167. package/dist/server/tool-extra.test.d.ts +1 -0
  168. package/dist/server/tool-extra.test.js +167 -0
  169. package/dist/server/tool-extra.test.js.map +1 -0
  170. package/dist/server/view-name.test-d.d.ts +1 -0
  171. package/dist/server/view-name.test-d.js +8 -0
  172. package/dist/server/view-name.test-d.js.map +1 -0
  173. package/dist/server/view-resource-resolution.test.js +81 -8
  174. package/dist/server/view-resource-resolution.test.js.map +1 -1
  175. package/dist/server/viewsDevServer.js +4 -1
  176. package/dist/server/viewsDevServer.js.map +1 -1
  177. package/dist/test/utils.d.ts +9 -11
  178. package/dist/test/utils.js +220 -201
  179. package/dist/test/utils.js.map +1 -1
  180. package/dist/test/view.test.js +44 -40
  181. package/dist/test/view.test.js.map +1 -1
  182. package/dist/views/index.d.ts +10 -0
  183. package/dist/views/index.js +3 -0
  184. package/dist/views/index.js.map +1 -0
  185. package/dist/{web/plugin → views}/scan-views.js +1 -1
  186. package/dist/views/scan-views.js.map +1 -0
  187. package/dist/views/scan-views.test.d.ts +1 -0
  188. package/dist/views/scan-views.test.js.map +1 -0
  189. package/dist/views/validate-view.d.ts +1 -0
  190. package/dist/{web/plugin → views}/validate-view.js +2 -2
  191. package/dist/views/validate-view.js.map +1 -0
  192. package/dist/views/validate-view.test.d.ts +1 -0
  193. package/dist/views/validate-view.test.js.map +1 -0
  194. package/dist/web/bridges/adaptor.d.ts +14 -3
  195. package/dist/web/bridges/adaptor.js +185 -18
  196. package/dist/web/bridges/adaptor.js.map +1 -1
  197. package/dist/web/bridges/adaptor.test.js +95 -11
  198. package/dist/web/bridges/adaptor.test.js.map +1 -1
  199. package/dist/web/bridges/apps-sdk/bridge.js +1 -1
  200. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  201. package/dist/web/bridges/apps-sdk/types.d.ts +2 -3
  202. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  203. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +4 -4
  204. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +4 -4
  205. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  206. package/dist/web/bridges/get-adaptor.test.js +2 -2
  207. package/dist/web/bridges/get-adaptor.test.js.map +1 -1
  208. package/dist/web/bridges/mcp-app/bridge.d.ts +1 -1
  209. package/dist/web/bridges/mcp-app/bridge.js +15 -6
  210. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  211. package/dist/web/bridges/mcp-app/bridge.test.js +2 -2
  212. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -1
  213. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  214. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  215. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
  216. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  217. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  218. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  219. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  220. package/dist/web/bridges/mcp-app/view-tools.test.js +1 -1
  221. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  222. package/dist/web/bridges/types.d.ts +74 -16
  223. package/dist/web/bridges/types.js +1 -1
  224. package/dist/web/bridges/types.js.map +1 -1
  225. package/dist/web/components/modal-provider.d.ts +1 -1
  226. package/dist/web/create-store.test.js +2 -2
  227. package/dist/web/create-store.test.js.map +1 -1
  228. package/dist/web/data-llm.d.ts +1 -1
  229. package/dist/web/data-llm.js +3 -2
  230. package/dist/web/data-llm.js.map +1 -1
  231. package/dist/web/data-llm.test.js +17 -2
  232. package/dist/web/data-llm.test.js.map +1 -1
  233. package/dist/web/generate-helpers.d.ts +23 -19
  234. package/dist/web/generate-helpers.js +21 -17
  235. package/dist/web/generate-helpers.js.map +1 -1
  236. package/dist/web/generate-helpers.test-d.js +3 -3
  237. package/dist/web/generate-helpers.test-d.js.map +1 -1
  238. package/dist/web/generate-helpers.test.js +2 -2
  239. package/dist/web/generate-helpers.test.js.map +1 -1
  240. package/dist/web/hooks/index.d.ts +6 -1
  241. package/dist/web/hooks/index.js +6 -1
  242. package/dist/web/hooks/index.js.map +1 -1
  243. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  244. package/dist/web/hooks/openai-extensions.test.js +107 -0
  245. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  246. package/dist/web/hooks/test/utils.d.ts +2 -1
  247. package/dist/web/hooks/test/utils.js +1 -1
  248. package/dist/web/hooks/test/utils.js.map +1 -1
  249. package/dist/web/hooks/use-call-tool.d.ts +2 -2
  250. package/dist/web/hooks/use-call-tool.js +15 -10
  251. package/dist/web/hooks/use-call-tool.js.map +1 -1
  252. package/dist/web/hooks/use-call-tool.test.js +15 -4
  253. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  254. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  255. package/dist/web/hooks/use-deep-link.js +34 -0
  256. package/dist/web/hooks/use-deep-link.js.map +1 -0
  257. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  258. package/dist/web/hooks/use-display-mode.js +1 -1
  259. package/dist/web/hooks/use-display-mode.js.map +1 -1
  260. package/dist/web/hooks/use-display-mode.test.js +1 -1
  261. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  262. package/dist/web/hooks/use-download.d.ts +1 -3
  263. package/dist/web/hooks/use-download.js +1 -2
  264. package/dist/web/hooks/use-download.js.map +1 -1
  265. package/dist/web/hooks/use-download.test.js +7 -7
  266. package/dist/web/hooks/use-download.test.js.map +1 -1
  267. package/dist/web/hooks/use-file-resource.d.ts +37 -0
  268. package/dist/web/hooks/use-file-resource.js +98 -0
  269. package/dist/web/hooks/use-file-resource.js.map +1 -0
  270. package/dist/web/hooks/use-file-resource.test.d.ts +1 -0
  271. package/dist/web/hooks/use-file-resource.test.js +65 -0
  272. package/dist/web/hooks/use-file-resource.test.js.map +1 -0
  273. package/dist/web/hooks/use-files.test.js +1 -1
  274. package/dist/web/hooks/use-files.test.js.map +1 -1
  275. package/dist/web/hooks/use-host.d.ts +44 -0
  276. package/dist/web/hooks/use-host.js +45 -0
  277. package/dist/web/hooks/use-host.js.map +1 -0
  278. package/dist/web/hooks/use-host.test.d.ts +1 -0
  279. package/dist/web/hooks/use-host.test.js +59 -0
  280. package/dist/web/hooks/use-host.test.js.map +1 -0
  281. package/dist/web/hooks/use-model-context.d.ts +44 -0
  282. package/dist/web/hooks/use-model-context.js +63 -0
  283. package/dist/web/hooks/use-model-context.js.map +1 -0
  284. package/dist/web/hooks/use-open-external.test.js +2 -2
  285. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  286. package/dist/web/hooks/use-open-file.d.ts +20 -0
  287. package/dist/web/hooks/use-open-file.js +25 -0
  288. package/dist/web/hooks/use-open-file.js.map +1 -0
  289. package/dist/web/hooks/use-register-view-tool.d.ts +3 -4
  290. package/dist/web/hooks/use-register-view-tool.js +1 -1
  291. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  292. package/dist/web/hooks/use-request-close.test.js +1 -1
  293. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  294. package/dist/web/hooks/use-request-modal.test.js +1 -1
  295. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  296. package/dist/web/hooks/use-request-size.d.ts +1 -1
  297. package/dist/web/hooks/use-request-size.js +1 -1
  298. package/dist/web/hooks/use-request-size.js.map +1 -1
  299. package/dist/web/hooks/use-request-size.test.js +1 -1
  300. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  301. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  302. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  303. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  304. package/dist/web/hooks/use-set-open-in-app-url.test.js +2 -8
  305. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  306. package/dist/web/hooks/use-tool-info.d.ts +1 -20
  307. package/dist/web/hooks/use-tool-info.js +0 -1
  308. package/dist/web/hooks/use-tool-info.js.map +1 -1
  309. package/dist/web/hooks/use-tool-info.test-d.js +0 -5
  310. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  311. package/dist/web/hooks/use-tool-info.test.js +2 -7
  312. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  313. package/dist/web/hooks/use-user.d.ts +3 -2
  314. package/dist/web/hooks/use-user.js +4 -3
  315. package/dist/web/hooks/use-user.js.map +1 -1
  316. package/dist/web/hooks/use-user.test.js +5 -3
  317. package/dist/web/hooks/use-user.test.js.map +1 -1
  318. package/dist/web/hooks/use-view-state.js +19 -9
  319. package/dist/web/hooks/use-view-state.js.map +1 -1
  320. package/dist/web/hooks/use-view-state.test.js +33 -2
  321. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  322. package/dist/web/hooks/use-viewport.d.ts +20 -0
  323. package/dist/web/hooks/use-viewport.js +21 -0
  324. package/dist/web/hooks/use-viewport.js.map +1 -0
  325. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  326. package/dist/web/hooks/{use-layout.test.js → use-viewport.test.js} +12 -32
  327. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  328. package/dist/web/mount-view.d.ts +3 -2
  329. package/dist/web/mount-view.js +5 -8
  330. package/dist/web/mount-view.js.map +1 -1
  331. package/package.json +34 -29
  332. package/dist/cli/resolve-views-dir.d.ts +0 -1
  333. package/dist/cli/resolve-views-dir.js.map +0 -1
  334. package/dist/web/hooks/use-layout.d.ts +0 -24
  335. package/dist/web/hooks/use-layout.js +0 -25
  336. package/dist/web/hooks/use-layout.js.map +0 -1
  337. package/dist/web/hooks/use-layout.test.js.map +0 -1
  338. package/dist/web/plugin/data-llm.test.js +0 -81
  339. package/dist/web/plugin/data-llm.test.js.map +0 -1
  340. package/dist/web/plugin/plugin.d.ts +0 -33
  341. package/dist/web/plugin/plugin.js +0 -189
  342. package/dist/web/plugin/plugin.js.map +0 -1
  343. package/dist/web/plugin/scan-views.js.map +0 -1
  344. package/dist/web/plugin/scan-views.test.js.map +0 -1
  345. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  346. package/dist/web/plugin/transform-data-llm.js +0 -96
  347. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  348. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  349. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  350. package/dist/web/plugin/validate-view.d.ts +0 -1
  351. package/dist/web/plugin/validate-view.js.map +0 -1
  352. package/dist/web/plugin/validate-view.test.js.map +0 -1
  353. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  354. /package/dist/{web/plugin/data-llm.test.d.ts → context-warnings.test.d.ts} +0 -0
  355. /package/dist/{web/plugin/scan-views.test.d.ts → server/app.test.d.ts} +0 -0
  356. /package/dist/{web/plugin/validate-view.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  357. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  358. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  359. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  360. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -1,14 +1,51 @@
1
- import { type BearerAuthMiddlewareOptions } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
1
+ import { type BearerAuthMiddlewareOptions } from "@modelcontextprotocol/express";
2
+ import type { AuthInfo as SdkAuthInfo } from "@modelcontextprotocol/server";
2
3
  import type { RequestHandler } from "express";
3
- export { InvalidTokenError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
4
- export { type BearerAuthMiddlewareOptions, requireBearerAuth, } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
5
- export { type AuthMetadataOptions, mcpAuthMetadataRouter, } from "@modelcontextprotocol/sdk/server/auth/router.js";
6
- export type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
4
+ export { type AuthMetadataOptions, type BearerAuthMiddlewareOptions, mcpAuthMetadataRouter, requireBearerAuth, } from "@modelcontextprotocol/express";
5
+ export { OAuthError, OAuthErrorCode } from "@modelcontextprotocol/server";
6
+ /** Claims a verifier puts in `AuthInfo["extra"]`: any JSON-ish bag of them. */
7
+ export type ExtraClaims = Record<string, unknown>;
8
+ /**
9
+ * A validated access token, as resolved by a
10
+ * [verifier](https://docs.skybridge.tech/api-reference/verifier) and handed to
11
+ * handlers on `extra.http?.authInfo`.
12
+ *
13
+ * Unparameterized, `extra` stays the SDK's `Record<string, unknown>` bag. The
14
+ * claims are owned by whoever verifies the token: parameterize the verifier and
15
+ * the shape flows through {@link OAuthConfig} to every handler.
16
+ *
17
+ * @typeParam TExtra - Claims populated in `extra`.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * type Claims = { subject?: string; email?: string };
22
+ *
23
+ * async function verifyAccessToken(token: string): Promise<AuthInfo<Claims>> {
24
+ * // ...
25
+ * }
26
+ * ```
27
+ */
28
+ export type AuthInfo<TExtra extends ExtraClaims = ExtraClaims> = Omit<SdkAuthInfo, "extra"> & {
29
+ extra?: TExtra;
30
+ };
31
+ /**
32
+ * Checks a bearer token and resolves the claims it carries. The type parameter
33
+ * is what makes `extra.http?.authInfo.extra` typed downstream, so a verifier is the
34
+ * single source for the claim shape.
35
+ *
36
+ * Pass one to {@link requireBearerAuth} or {@link optionalBearerAuth} directly,
37
+ * or hand it to the `oauth` server option inside an {@link OAuthConfig}.
38
+ *
39
+ * @typeParam TExtra - Claims this verifier populates in `AuthInfo["extra"]`.
40
+ */
41
+ export type TokenVerifier<TExtra extends ExtraClaims = ExtraClaims> = {
42
+ verifyAccessToken(token: string): Promise<AuthInfo<TExtra>>;
43
+ };
7
44
  /**
8
45
  * Like `requireBearerAuth`, but lets requests through when no
9
46
  * `Authorization` header is present. Used for mixed-auth servers where some
10
47
  * tools are public and others require sign-in: each tool enforces its own
11
- * `securitySchemes` against `extra.authInfo`.
48
+ * `securitySchemes` against `extra.http?.authInfo`.
12
49
  *
13
50
  * Behavior:
14
51
  * - No `Authorization` header → `next()` without `req.auth`.
@@ -1,12 +1,11 @@
1
- import { requireBearerAuth, } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
2
- export { InvalidTokenError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
3
- export { requireBearerAuth, } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
4
- export { mcpAuthMetadataRouter, } from "@modelcontextprotocol/sdk/server/auth/router.js";
1
+ import { requireBearerAuth, } from "@modelcontextprotocol/express";
2
+ export { mcpAuthMetadataRouter, requireBearerAuth, } from "@modelcontextprotocol/express";
3
+ export { OAuthError, OAuthErrorCode } from "@modelcontextprotocol/server";
5
4
  /**
6
5
  * Like `requireBearerAuth`, but lets requests through when no
7
6
  * `Authorization` header is present. Used for mixed-auth servers where some
8
7
  * tools are public and others require sign-in: each tool enforces its own
9
- * `securitySchemes` against `extra.authInfo`.
8
+ * `securitySchemes` against `extra.http?.authInfo`.
10
9
  *
11
10
  * Behavior:
12
11
  * - No `Authorization` header → `next()` without `req.auth`.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,iBAAiB,GAClB,MAAM,gEAAgE,CAAC;AAIxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AACpF,OAAO,EAEL,iBAAiB,GAClB,MAAM,gEAAgE,CAAC;AACxE,OAAO,EAEL,qBAAqB,GACtB,MAAM,iDAAiD,CAAC;AAGzD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAoC;IAEpC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC/B,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,OAAO,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import {\n type BearerAuthMiddlewareOptions,\n requireBearerAuth,\n} from \"@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js\";\n\nimport type { RequestHandler } from \"express\";\n\nexport { InvalidTokenError } from \"@modelcontextprotocol/sdk/server/auth/errors.js\";\nexport {\n type BearerAuthMiddlewareOptions,\n requireBearerAuth,\n} from \"@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js\";\nexport {\n type AuthMetadataOptions,\n mcpAuthMetadataRouter,\n} from \"@modelcontextprotocol/sdk/server/auth/router.js\";\nexport type { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types.js\";\n\n/**\n * Like `requireBearerAuth`, but lets requests through when no\n * `Authorization` header is present. Used for mixed-auth servers where some\n * tools are public and others require sign-in: each tool enforces its own\n * `securitySchemes` against `extra.authInfo`.\n *\n * Behavior:\n * - No `Authorization` header → `next()` without `req.auth`.\n * - Valid Bearer token → `req.auth` set, same as `requireBearerAuth`.\n * - Invalid / malformed / expired / insufficient-scope → same error response\n * as `requireBearerAuth` (401/403). Sending a bad token is still a client\n * error.\n */\nexport function optionalBearerAuth(\n options: BearerAuthMiddlewareOptions,\n): RequestHandler {\n const required = requireBearerAuth(options);\n return (req, res, next) => {\n if (!req.headers.authorization) {\n next();\n return;\n }\n return required(req, res, next);\n };\n}\n"]}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,iBAAiB,GAClB,MAAM,+BAA+B,CAAC;AAKvC,OAAO,EAGL,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AA2C1E;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAoC;IAEpC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC/B,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,OAAO,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import {\n type BearerAuthMiddlewareOptions,\n requireBearerAuth,\n} from \"@modelcontextprotocol/express\";\nimport type { AuthInfo as SdkAuthInfo } from \"@modelcontextprotocol/server\";\n\nimport type { RequestHandler } from \"express\";\n\nexport {\n type AuthMetadataOptions,\n type BearerAuthMiddlewareOptions,\n mcpAuthMetadataRouter,\n requireBearerAuth,\n} from \"@modelcontextprotocol/express\";\nexport { OAuthError, OAuthErrorCode } from \"@modelcontextprotocol/server\";\n/** Claims a verifier puts in `AuthInfo[\"extra\"]`: any JSON-ish bag of them. */\nexport type ExtraClaims = Record<string, unknown>;\n\n/**\n * A validated access token, as resolved by a\n * [verifier](https://docs.skybridge.tech/api-reference/verifier) and handed to\n * handlers on `extra.http?.authInfo`.\n *\n * Unparameterized, `extra` stays the SDK's `Record<string, unknown>` bag. The\n * claims are owned by whoever verifies the token: parameterize the verifier and\n * the shape flows through {@link OAuthConfig} to every handler.\n *\n * @typeParam TExtra - Claims populated in `extra`.\n *\n * @example\n * ```ts\n * type Claims = { subject?: string; email?: string };\n *\n * async function verifyAccessToken(token: string): Promise<AuthInfo<Claims>> {\n * // ...\n * }\n * ```\n */\nexport type AuthInfo<TExtra extends ExtraClaims = ExtraClaims> = Omit<\n SdkAuthInfo,\n \"extra\"\n> & { extra?: TExtra };\n\n/**\n * Checks a bearer token and resolves the claims it carries. The type parameter\n * is what makes `extra.http?.authInfo.extra` typed downstream, so a verifier is the\n * single source for the claim shape.\n *\n * Pass one to {@link requireBearerAuth} or {@link optionalBearerAuth} directly,\n * or hand it to the `oauth` server option inside an {@link OAuthConfig}.\n *\n * @typeParam TExtra - Claims this verifier populates in `AuthInfo[\"extra\"]`.\n */\nexport type TokenVerifier<TExtra extends ExtraClaims = ExtraClaims> = {\n verifyAccessToken(token: string): Promise<AuthInfo<TExtra>>;\n};\n\n/**\n * Like `requireBearerAuth`, but lets requests through when no\n * `Authorization` header is present. Used for mixed-auth servers where some\n * tools are public and others require sign-in: each tool enforces its own\n * `securitySchemes` against `extra.http?.authInfo`.\n *\n * Behavior:\n * - No `Authorization` header → `next()` without `req.auth`.\n * - Valid Bearer token → `req.auth` set, same as `requireBearerAuth`.\n * - Invalid / malformed / expired / insufficient-scope → same error response\n * as `requireBearerAuth` (401/403). Sending a bad token is still a client\n * error.\n */\nexport function optionalBearerAuth(\n options: BearerAuthMiddlewareOptions,\n): RequestHandler {\n const required = requireBearerAuth(options);\n return (req, res, next) => {\n if (!req.headers.authorization) {\n next();\n return;\n }\n return required(req, res, next);\n };\n}\n"]}
@@ -4,7 +4,7 @@ function manifestOf(server) {
4
4
  return server.viteManifest;
5
5
  }
6
6
  function makeServer() {
7
- return new McpServer({ name: "test", version: "0.0.1" }, { capabilities: {} });
7
+ return new McpServer({ name: "test", version: "0.0.1" });
8
8
  }
9
9
  describe("__setBuildManifest", () => {
10
10
  it("primes the Vite manifest for the next McpServer constructed", () => {
@@ -16,12 +16,13 @@ describe("__setBuildManifest", () => {
16
16
  // generated `dist/__entry.js` relies on.
17
17
  expect(manifestOf(makeServer())).toEqual(manifest);
18
18
  });
19
- it("is consume-once: a second McpServer built without re-priming gets no manifest", () => {
20
- __setBuildManifest({
19
+ it("keeps priming every McpServer the app factory builds per request", () => {
20
+ const manifest = {
21
21
  "src/views/index.tsx": { file: "assets/index-CAFEBABE.js" },
22
- });
23
- makeServer(); // consumes the primed manifest
24
- expect(manifestOf(makeServer())).toBeNull();
22
+ };
23
+ __setBuildManifest(manifest);
24
+ makeServer();
25
+ expect(manifestOf(makeServer())).toEqual(manifest);
25
26
  });
26
27
  });
27
28
  //# sourceMappingURL=build-manifest.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-manifest.test.js","sourceRoot":"","sources":["../../src/server/build-manifest.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE3D,SAAS,UAAU,CACjB,MAAiB;IAEjB,OACE,MAGD,CAAC,YAAY,CAAC;AACjB,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,IAAI,SAAS,CAClB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAClC,EAAE,YAAY,EAAE,EAAE,EAAE,CACrB,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,QAAQ,GAAG;YACf,qBAAqB,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE;SAC5D,CAAC;QACF,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAE7B,uEAAuE;QACvE,yCAAyC;QACzC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,kBAAkB,CAAC;YACjB,qBAAqB,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE;SAC5D,CAAC,CAAC;QAEH,UAAU,EAAE,CAAC,CAAC,+BAA+B;QAC7C,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { __setBuildManifest, McpServer } from \"./index.js\";\n\nfunction manifestOf(\n server: McpServer,\n): Record<string, { file: string }> | null {\n return (\n server as unknown as {\n viteManifest: Record<string, { file: string }> | null;\n }\n ).viteManifest;\n}\n\nfunction makeServer(): McpServer {\n return new McpServer(\n { name: \"test\", version: \"0.0.1\" },\n { capabilities: {} },\n );\n}\n\ndescribe(\"__setBuildManifest\", () => {\n it(\"primes the Vite manifest for the next McpServer constructed\", () => {\n const manifest = {\n \"src/views/index.tsx\": { file: \"assets/index-DEADBEEF.js\" },\n };\n __setBuildManifest(manifest);\n\n // viteManifest is private; reach into it to lock the contract that the\n // generated `dist/__entry.js` relies on.\n expect(manifestOf(makeServer())).toEqual(manifest);\n });\n\n it(\"is consume-once: a second McpServer built without re-priming gets no manifest\", () => {\n __setBuildManifest({\n \"src/views/index.tsx\": { file: \"assets/index-CAFEBABE.js\" },\n });\n\n makeServer(); // consumes the primed manifest\n expect(manifestOf(makeServer())).toBeNull();\n });\n});\n"]}
1
+ {"version":3,"file":"build-manifest.test.js","sourceRoot":"","sources":["../../src/server/build-manifest.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE3D,SAAS,UAAU,CACjB,MAAiB;IAEjB,OACE,MAGD,CAAC,YAAY,CAAC;AACjB,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,QAAQ,GAAG;YACf,qBAAqB,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE;SAC5D,CAAC;QACF,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAE7B,uEAAuE;QACvE,yCAAyC;QACzC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,QAAQ,GAAG;YACf,qBAAqB,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE;SAC5D,CAAC;QACF,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAE7B,UAAU,EAAE,CAAC;QACb,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { __setBuildManifest, McpServer } from \"./index.js\";\n\nfunction manifestOf(\n server: McpServer,\n): Record<string, { file: string }> | null {\n return (\n server as unknown as {\n viteManifest: Record<string, { file: string }> | null;\n }\n ).viteManifest;\n}\n\nfunction makeServer(): McpServer {\n return new McpServer({ name: \"test\", version: \"0.0.1\" });\n}\n\ndescribe(\"__setBuildManifest\", () => {\n it(\"primes the Vite manifest for the next McpServer constructed\", () => {\n const manifest = {\n \"src/views/index.tsx\": { file: \"assets/index-DEADBEEF.js\" },\n };\n __setBuildManifest(manifest);\n\n // viteManifest is private; reach into it to lock the contract that the\n // generated `dist/__entry.js` relies on.\n expect(manifestOf(makeServer())).toEqual(manifest);\n });\n\n it(\"keeps priming every McpServer the app factory builds per request\", () => {\n const manifest = {\n \"src/views/index.tsx\": { file: \"assets/index-CAFEBABE.js\" },\n };\n __setBuildManifest(manifest);\n\n makeServer();\n expect(manifestOf(makeServer())).toEqual(manifest);\n });\n});\n"]}
@@ -1,4 +1,4 @@
1
- import type { AudioContent, EmbeddedResource, ImageContent, ResourceLink, TextContent } from "@modelcontextprotocol/sdk/types.js";
1
+ import type { AudioContent, EmbeddedResource, ImageContent, ResourceLink, TextContent } from "@modelcontextprotocol/server";
2
2
  /**
3
3
  * MCP content annotations applied to any returned block.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"content-helpers.js","sourceRoot":"","sources":["../../src/server/content-helpers.ts"],"names":[],"mappings":"AAqBA;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,IAAyB;IACzC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,IAAI,CAClB,KAAa,EACb,WAAgC;IAEhC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAEoD,EACpD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,IAOC,EACD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,GAAG,IAAI;QACP,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type {\n AudioContent,\n EmbeddedResource,\n ImageContent,\n ResourceLink,\n TextContent,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * MCP content annotations applied to any returned block.\n *\n * - `audience` — who is meant to see the content (`\"user\"`, `\"assistant\"`, or both).\n * - `priority` — relative importance hint for the host.\n * - `lastModified` — ISO timestamp for when the content was produced.\n */\ntype ContentAnnotations = {\n audience?: (\"user\" | \"assistant\")[];\n priority?: number;\n lastModified?: string;\n};\n\n/**\n * Returns a base64-encoded string.\n * - `Uint8Array` input is encoded via `Buffer.toString(\"base64\")`.\n * - `string` input is assumed to be **already base64-encoded** and is returned\n * as-is. Passing raw/unencoded string bytes will produce invalid MCP content.\n */\nfunction toBase64(data: string | Uint8Array): string {\n if (typeof data === \"string\") {\n return data;\n }\n return Buffer.from(data).toString(\"base64\");\n}\n\n/**\n * Build an MCP text content block.\n *\n * @example\n * ```ts\n * return { content: [text(\"Found 3 results.\")] };\n * ```\n */\nexport function text(\n value: string,\n annotations?: ContentAnnotations,\n): TextContent {\n return { type: \"text\", text: value, ...(annotations && { annotations }) };\n}\n\n/**\n * Build an MCP image content block.\n *\n * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is\n * **already base64-encoded**. Passing a raw byte-string will produce invalid\n * content.\n */\nexport function image(\n data: string | Uint8Array,\n mimeType: string,\n annotations?: ContentAnnotations,\n): ImageContent {\n return {\n type: \"image\",\n data: toBase64(data),\n mimeType,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP audio content block.\n *\n * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is\n * **already base64-encoded**.\n */\nexport function audio(\n data: string | Uint8Array,\n mimeType: string,\n annotations?: ContentAnnotations,\n): AudioContent {\n return {\n type: \"audio\",\n data: toBase64(data),\n mimeType,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP embedded resource — the full content travels inline. Use this\n * when the client needs the bytes themselves rather than a link.\n *\n * Pass either `text` (UTF-8 string) or `blob` (base64-encoded bytes).\n */\nexport function embeddedResource(\n resource:\n | { uri: string; mimeType?: string; text: string }\n | { uri: string; mimeType?: string; blob: string },\n annotations?: ContentAnnotations,\n): EmbeddedResource {\n return {\n type: \"resource\",\n resource,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP resource link — a `type: \"resource_link\"` block carrying a URI\n * the client can fetch (or subscribe to) on demand. Use a link when the\n * client should retrieve the bytes itself; use {@link embeddedResource} when\n * the content must travel inline with the response.\n */\nexport function resourceLink(\n link: {\n uri: string;\n name: string;\n title?: string;\n description?: string;\n mimeType?: string;\n size?: number;\n },\n annotations?: ContentAnnotations,\n): ResourceLink {\n return {\n type: \"resource_link\",\n ...link,\n ...(annotations && { annotations }),\n };\n}\n"]}
1
+ {"version":3,"file":"content-helpers.js","sourceRoot":"","sources":["../../src/server/content-helpers.ts"],"names":[],"mappings":"AAqBA;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,IAAyB;IACzC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,IAAI,CAClB,KAAa,EACb,WAAgC;IAEhC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAEoD,EACpD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,IAOC,EACD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,GAAG,IAAI;QACP,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type {\n AudioContent,\n EmbeddedResource,\n ImageContent,\n ResourceLink,\n TextContent,\n} from \"@modelcontextprotocol/server\";\n\n/**\n * MCP content annotations applied to any returned block.\n *\n * - `audience` — who is meant to see the content (`\"user\"`, `\"assistant\"`, or both).\n * - `priority` — relative importance hint for the host.\n * - `lastModified` — ISO timestamp for when the content was produced.\n */\ntype ContentAnnotations = {\n audience?: (\"user\" | \"assistant\")[];\n priority?: number;\n lastModified?: string;\n};\n\n/**\n * Returns a base64-encoded string.\n * - `Uint8Array` input is encoded via `Buffer.toString(\"base64\")`.\n * - `string` input is assumed to be **already base64-encoded** and is returned\n * as-is. Passing raw/unencoded string bytes will produce invalid MCP content.\n */\nfunction toBase64(data: string | Uint8Array): string {\n if (typeof data === \"string\") {\n return data;\n }\n return Buffer.from(data).toString(\"base64\");\n}\n\n/**\n * Build an MCP text content block.\n *\n * @example\n * ```ts\n * return { content: [text(\"Found 3 results.\")] };\n * ```\n */\nexport function text(\n value: string,\n annotations?: ContentAnnotations,\n): TextContent {\n return { type: \"text\", text: value, ...(annotations && { annotations }) };\n}\n\n/**\n * Build an MCP image content block.\n *\n * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is\n * **already base64-encoded**. Passing a raw byte-string will produce invalid\n * content.\n */\nexport function image(\n data: string | Uint8Array,\n mimeType: string,\n annotations?: ContentAnnotations,\n): ImageContent {\n return {\n type: \"image\",\n data: toBase64(data),\n mimeType,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP audio content block.\n *\n * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is\n * **already base64-encoded**.\n */\nexport function audio(\n data: string | Uint8Array,\n mimeType: string,\n annotations?: ContentAnnotations,\n): AudioContent {\n return {\n type: \"audio\",\n data: toBase64(data),\n mimeType,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP embedded resource — the full content travels inline. Use this\n * when the client needs the bytes themselves rather than a link.\n *\n * Pass either `text` (UTF-8 string) or `blob` (base64-encoded bytes).\n */\nexport function embeddedResource(\n resource:\n | { uri: string; mimeType?: string; text: string }\n | { uri: string; mimeType?: string; blob: string },\n annotations?: ContentAnnotations,\n): EmbeddedResource {\n return {\n type: \"resource\",\n resource,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP resource link — a `type: \"resource_link\"` block carrying a URI\n * the client can fetch (or subscribe to) on demand. Use a link when the\n * client should retrieve the bytes itself; use {@link embeddedResource} when\n * the content must travel inline with the response.\n */\nexport function resourceLink(\n link: {\n uri: string;\n name: string;\n title?: string;\n description?: string;\n mimeType?: string;\n size?: number;\n },\n annotations?: ContentAnnotations,\n): ResourceLink {\n return {\n type: \"resource_link\",\n ...link,\n ...(annotations && { annotations }),\n };\n}\n"]}
@@ -0,0 +1,113 @@
1
+ import { type McpServer as SdkMcpServer, type StandardSchemaV1, type StandardSchemaWithJSON } from "@modelcontextprotocol/server";
2
+ /**
3
+ * A webhook subscription, as passed to `onSubscribe`. Whatever delivers the
4
+ * events POSTs them to `url`, signed with `secret`, until `expiresAt`.
5
+ */
6
+ export interface EventSubscription {
7
+ /** Stable across refreshes: the same user subscribing to the same event with the same arguments and callback gets the same `id`. */
8
+ id: string;
9
+ /** Callback URL deliveries are POSTed to. */
10
+ url: string;
11
+ /** Standard Webhooks signing secret (`whsec_…`). A refresh may carry a new one. */
12
+ secret: string;
13
+ /** When the subscription lapses unless the host refreshes it. */
14
+ expiresAt: Date;
15
+ }
16
+ /** An event occurrence, as passed to {@link deliverEvent}. */
17
+ export interface EventOccurrence {
18
+ /** Event type name, as registered with `registerEvent`. */
19
+ name: string;
20
+ /** Stable identifier the host uses to drop duplicates, ideally the upstream's. Reuse it when retrying. */
21
+ id: string;
22
+ /** When the event happened. Defaults to now. */
23
+ timestamp?: Date;
24
+ /** Payload matching the event's `payloadSchema`. */
25
+ data: unknown;
26
+ }
27
+ /** Outcome of {@link deliverEvent}. Retry with the same event `id` when `retryable`. */
28
+ export type DeliveryResult = {
29
+ ok: true;
30
+ } | {
31
+ ok: false;
32
+ reason: string;
33
+ retryable: boolean;
34
+ status?: number;
35
+ };
36
+ type EventSchema = Record<string, StandardSchemaWithJSON> | StandardSchemaWithJSON;
37
+ export type InferEventSchema<T extends EventSchema> = T extends StandardSchemaWithJSON ? StandardSchemaV1.InferOutput<T> : T extends Record<string, StandardSchemaWithJSON> ? {
38
+ [K in keyof T as undefined extends StandardSchemaV1.InferOutput<T[K]> ? never : K]: StandardSchemaV1.InferOutput<T[K]>;
39
+ } & {
40
+ [K in keyof T as undefined extends StandardSchemaV1.InferOutput<T[K]> ? K : never]?: StandardSchemaV1.InferOutput<T[K]>;
41
+ } : never;
42
+ /** The `registerEvent` config: how the event type is described in `events/list`. */
43
+ export interface EventConfig<TInput extends EventSchema> {
44
+ /** Stable, specific name such as `comment.created`. */
45
+ name: string;
46
+ /** What the event is and when it fires. */
47
+ description?: string;
48
+ /** Subscription arguments (filters): a Zod shape or a Standard Schema object. */
49
+ inputSchema?: TInput;
50
+ /** Shape of the delivered `data`: a Zod shape or a Standard Schema object. */
51
+ payloadSchema: EventSchema;
52
+ _meta?: Record<string, unknown>;
53
+ }
54
+ /** What `registerEvent` does when the host subscribes and unsubscribes. */
55
+ export interface EventHooks<TArguments, TExtra> {
56
+ /**
57
+ * Runs on every `events/subscribe`, including the host's refreshes, once
58
+ * the callback URL is verified. Hand the subscription to whatever delivers
59
+ * the events, keyed by `subscription.id`. Throw (e.g. a `ProtocolError`) to
60
+ * reject it, for instance when the user may not access what the arguments
61
+ * point to.
62
+ */
63
+ onSubscribe(args: TArguments, context: {
64
+ subscription: EventSubscription;
65
+ extra: TExtra;
66
+ }): void | Promise<void>;
67
+ /** Runs on `events/unsubscribe`. Stop delivering to `subscription.id`. */
68
+ onUnsubscribe(args: TArguments, context: {
69
+ subscription: Pick<EventSubscription, "id">;
70
+ extra: TExtra;
71
+ }): void | Promise<void>;
72
+ }
73
+ /**
74
+ * @experimental POST one event to a subscription handed out by `onSubscribe`,
75
+ * as MCP Events expects: the event envelope, Standard Webhooks signature
76
+ * headers, a 10 second deadline and, outside development, no requests to
77
+ * private addresses. Pass the old and new secrets during a rotation so both
78
+ * sign the delivery. A subscription past `expiresAt` is not posted to.
79
+ * Retrying is up to the caller. API may change.
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * const result = await deliverEvent(subscription, {
84
+ * name: "comment.created",
85
+ * id: comment.id,
86
+ * data: { documentId: comment.documentId, excerpt: comment.text.slice(0, 280) },
87
+ * });
88
+ * if (!result.ok && result.retryable) {
89
+ * await queue.retryLater(subscription, comment);
90
+ * }
91
+ * ```
92
+ *
93
+ * @see https://docs.skybridge.tech/api-reference/register-event
94
+ */
95
+ export declare function deliverEvent(subscription: Pick<EventSubscription, "id" | "url"> & {
96
+ secret: string | string[];
97
+ expiresAt: Date | string;
98
+ }, event: EventOccurrence): Promise<DeliveryResult>;
99
+ /**
100
+ * The event types registered on one server, and the `events/*` handlers that
101
+ * serve them.
102
+ *
103
+ * @internal
104
+ */
105
+ export declare class EventRegistry {
106
+ private readonly server;
107
+ private readonly events;
108
+ constructor(server: Pick<SdkMcpServer["server"], "setRequestHandler">);
109
+ add(config: EventConfig<EventSchema>, hooks: EventHooks<never, never>): void;
110
+ private install;
111
+ private resolve;
112
+ }
113
+ export {};
@@ -0,0 +1,318 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
+ import http from "node:http";
3
+ import https from "node:https";
4
+ import { INVALID_PARAMS, ProtocolError, } from "@modelcontextprotocol/server";
5
+ import { globalHttpAgent, globalHttpsAgent } from "request-filtering-agent";
6
+ import { Webhook } from "standardwebhooks";
7
+ import { z } from "zod/v4";
8
+ const EVENTS_ERROR = {
9
+ NotFound: -32011,
10
+ Forbidden: -32012,
11
+ Unsupported: -32014,
12
+ CallbackEndpointError: -32015,
13
+ };
14
+ const MAX_PAYLOAD_BYTES = 256 * 1024;
15
+ const DELIVERY_TIMEOUT_MS = 10_000;
16
+ const VERIFICATION_CACHE_MS = 60 * 60_000;
17
+ const MIN_TTL_MS = 60_000;
18
+ const DEFAULT_TTL_MS = 30 * 60_000;
19
+ const MAX_TTL_MS = 24 * 60 * 60_000;
20
+ function toStandardSchema(schema) {
21
+ return "~standard" in schema
22
+ ? schema
23
+ : z.object(schema);
24
+ }
25
+ async function validate(schema, value) {
26
+ const result = await schema["~standard"].validate(value);
27
+ if (result.issues) {
28
+ throw new ProtocolError(INVALID_PARAMS, `Invalid arguments: ${result.issues.map((issue) => issue.message).join(", ")}`);
29
+ }
30
+ return result.value;
31
+ }
32
+ function canonicalJson(value) {
33
+ if (Array.isArray(value)) {
34
+ return `[${value.map(canonicalJson).join(",")}]`;
35
+ }
36
+ if (value && typeof value === "object") {
37
+ return `{${Object.keys(value)
38
+ .sort()
39
+ .map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
40
+ .join(",")}}`;
41
+ }
42
+ return JSON.stringify(value);
43
+ }
44
+ function subscriberOf(ctx) {
45
+ const authInfo = ctx.http?.authInfo;
46
+ const subject = authInfo?.extra?.subject;
47
+ const subscriber = typeof subject === "string" ? subject : authInfo?.clientId;
48
+ if (!subscriber) {
49
+ throw new ProtocolError(EVENTS_ERROR.Forbidden, "Webhook subscriptions require an authenticated caller");
50
+ }
51
+ return subscriber;
52
+ }
53
+ function isValidSecret(secret) {
54
+ const encoded = secret.startsWith("whsec_") ? secret.slice(6) : "";
55
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(encoded)) {
56
+ return false;
57
+ }
58
+ const length = Buffer.from(encoded, "base64").length;
59
+ return length >= 24 && length <= 64;
60
+ }
61
+ const insecureCallbacksAllowed = () => process.env.NODE_ENV !== "production";
62
+ function checkCallbackUrl(raw) {
63
+ let url;
64
+ try {
65
+ url = new URL(raw);
66
+ }
67
+ catch {
68
+ throw new ProtocolError(INVALID_PARAMS, "delivery.url is not a valid URL");
69
+ }
70
+ const allowed = url.protocol === "https:" ||
71
+ (url.protocol === "http:" && insecureCallbacksAllowed());
72
+ if (!allowed) {
73
+ throw new ProtocolError(INVALID_PARAMS, "delivery.url must use https");
74
+ }
75
+ return url.href;
76
+ }
77
+ function post(url, headers, body) {
78
+ const signal = AbortSignal.timeout(DELIVERY_TIMEOUT_MS);
79
+ const failure = (error) => ({
80
+ ok: false,
81
+ reason: signal.aborted
82
+ ? "timeout"
83
+ : error?.code?.startsWith("ERR_TLS") || error?.code?.includes("CERT")
84
+ ? "tls_error"
85
+ : "connection_refused",
86
+ });
87
+ const [client, agent] = url.startsWith("https:")
88
+ ? [https, globalHttpsAgent]
89
+ : [http, globalHttpAgent];
90
+ return new Promise((resolve) => {
91
+ const request = client.request(url, {
92
+ method: "POST",
93
+ headers: { ...headers, "content-length": Buffer.byteLength(body) },
94
+ signal,
95
+ ...(!insecureCallbacksAllowed() && { agent }),
96
+ }, (response) => {
97
+ const status = response.statusCode ?? 0;
98
+ const chunks = [];
99
+ let size = 0;
100
+ response.on("data", (chunk) => {
101
+ size += chunk.length;
102
+ if (size <= 64 * 1024) {
103
+ chunks.push(chunk);
104
+ }
105
+ });
106
+ response.on("end", () => {
107
+ if (status >= 200 && status < 300) {
108
+ resolve({ ok: true, body: Buffer.concat(chunks).toString() });
109
+ }
110
+ else {
111
+ resolve({
112
+ ok: false,
113
+ status,
114
+ reason: status >= 500 ? "http_5xx" : "http_4xx",
115
+ });
116
+ }
117
+ });
118
+ response.on("error", (error) => resolve(failure(error)));
119
+ response.on("close", () => resolve(failure()));
120
+ });
121
+ request.on("error", (error) => resolve(failure(error)));
122
+ request.end(body);
123
+ });
124
+ }
125
+ function signedPost(subscription, messageId, body) {
126
+ const signedAt = new Date();
127
+ const secrets = [subscription.secret].flat();
128
+ return post(subscription.url, {
129
+ "content-type": "application/json",
130
+ "webhook-id": messageId,
131
+ "webhook-timestamp": String(Math.floor(signedAt.getTime() / 1000)),
132
+ "webhook-signature": secrets
133
+ .map((secret) => new Webhook(secret).sign(messageId, signedAt, body))
134
+ .join(" "),
135
+ "x-mcp-subscription-id": subscription.id,
136
+ }, body);
137
+ }
138
+ /**
139
+ * @experimental POST one event to a subscription handed out by `onSubscribe`,
140
+ * as MCP Events expects: the event envelope, Standard Webhooks signature
141
+ * headers, a 10 second deadline and, outside development, no requests to
142
+ * private addresses. Pass the old and new secrets during a rotation so both
143
+ * sign the delivery. A subscription past `expiresAt` is not posted to.
144
+ * Retrying is up to the caller. API may change.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const result = await deliverEvent(subscription, {
149
+ * name: "comment.created",
150
+ * id: comment.id,
151
+ * data: { documentId: comment.documentId, excerpt: comment.text.slice(0, 280) },
152
+ * });
153
+ * if (!result.ok && result.retryable) {
154
+ * await queue.retryLater(subscription, comment);
155
+ * }
156
+ * ```
157
+ *
158
+ * @see https://docs.skybridge.tech/api-reference/register-event
159
+ */
160
+ export async function deliverEvent(subscription, event) {
161
+ if (!(new Date(subscription.expiresAt).getTime() > Date.now())) {
162
+ return { ok: false, reason: "expired", retryable: false };
163
+ }
164
+ const body = JSON.stringify({
165
+ eventId: event.id,
166
+ name: event.name,
167
+ timestamp: (event.timestamp ?? new Date()).toISOString(),
168
+ data: event.data,
169
+ cursor: null,
170
+ });
171
+ if (Buffer.byteLength(body) > MAX_PAYLOAD_BYTES) {
172
+ throw new Error(`Event "${event.name}" payload exceeds ${MAX_PAYLOAD_BYTES} bytes; send a summary and expose a tool to fetch the rest.`);
173
+ }
174
+ const outcome = await signedPost(subscription, event.id, body);
175
+ if (outcome.ok) {
176
+ return { ok: true };
177
+ }
178
+ const status = outcome.status ?? 0;
179
+ return {
180
+ ...outcome,
181
+ retryable: status !== 410 && status !== 413 && (status < 300 || status >= 400),
182
+ };
183
+ }
184
+ const verifiedCallbacks = new Map();
185
+ async function verifyCallback(subscriber, subscription) {
186
+ const key = `${subscriber}\n${subscription.url}`;
187
+ const now = Date.now();
188
+ if ((verifiedCallbacks.get(key) ?? 0) > now) {
189
+ return;
190
+ }
191
+ const challenge = randomBytes(24).toString("base64url");
192
+ const outcome = await signedPost(subscription, `msg_verification_${randomBytes(12).toString("hex")}`, JSON.stringify({ type: "verification", challenge }));
193
+ let echoed;
194
+ if (outcome.ok) {
195
+ try {
196
+ echoed = JSON.parse(outcome.body)?.challenge;
197
+ }
198
+ catch { }
199
+ }
200
+ const matched = typeof echoed === "string" &&
201
+ echoed.length === challenge.length &&
202
+ timingSafeEqual(Buffer.from(echoed), Buffer.from(challenge));
203
+ if (!matched) {
204
+ throw new ProtocolError(EVENTS_ERROR.CallbackEndpointError, "Callback endpoint verification failed", { reason: outcome.ok ? "challenge_failed" : outcome.reason });
205
+ }
206
+ for (const [cached, until] of verifiedCallbacks) {
207
+ if (until <= now) {
208
+ verifiedCallbacks.delete(cached);
209
+ }
210
+ }
211
+ verifiedCallbacks.set(key, now + VERIFICATION_CACHE_MS);
212
+ }
213
+ const SubscriptionKeySchema = z.object({
214
+ name: z.string(),
215
+ arguments: z.record(z.string(), z.unknown()).optional(),
216
+ delivery: z.object({ url: z.string() }),
217
+ });
218
+ const SubscribeParamsSchema = SubscriptionKeySchema.extend({
219
+ delivery: z.object({
220
+ mode: z.string().optional(),
221
+ url: z.string(),
222
+ secret: z.string(),
223
+ }),
224
+ cursor: z.string().nullable().optional(),
225
+ ttlMs: z.number().nullable().optional(),
226
+ });
227
+ /**
228
+ * The event types registered on one server, and the `events/*` handlers that
229
+ * serve them.
230
+ *
231
+ * @internal
232
+ */
233
+ export class EventRegistry {
234
+ server;
235
+ events = new Map();
236
+ constructor(server) {
237
+ this.server = server;
238
+ }
239
+ add(config, hooks) {
240
+ if (this.events.has(config.name)) {
241
+ throw new Error(`Event "${config.name}" is already registered.`);
242
+ }
243
+ if (this.events.size === 0) {
244
+ this.install();
245
+ }
246
+ this.events.set(config.name, {
247
+ name: config.name,
248
+ description: config.description,
249
+ inputSchema: toStandardSchema(config.inputSchema ?? {}),
250
+ payloadSchema: toStandardSchema(config.payloadSchema),
251
+ _meta: config._meta,
252
+ hooks,
253
+ });
254
+ }
255
+ install() {
256
+ this.server.setRequestHandler("events/list", { params: z.object({ cursor: z.string().optional() }).optional() }, () => ({
257
+ events: [...this.events.values()].map((event) => ({
258
+ name: event.name,
259
+ ...(event.description && { description: event.description }),
260
+ delivery: ["webhook"],
261
+ inputSchema: event.inputSchema["~standard"].jsonSchema.input({
262
+ target: "draft-2020-12",
263
+ }),
264
+ payloadSchema: event.payloadSchema["~standard"].jsonSchema.output({
265
+ target: "draft-2020-12",
266
+ }),
267
+ ...(event._meta && { _meta: event._meta }),
268
+ })),
269
+ }));
270
+ this.server.setRequestHandler("events/subscribe", { params: SubscribeParamsSchema }, async (params, ctx) => {
271
+ if (params.delivery.mode && params.delivery.mode !== "webhook") {
272
+ throw new ProtocolError(EVENTS_ERROR.Unsupported, `Unsupported delivery mode: ${params.delivery.mode}`, { feature: "deliveryMode", value: params.delivery.mode });
273
+ }
274
+ if (!isValidSecret(params.delivery.secret)) {
275
+ throw new ProtocolError(INVALID_PARAMS, "delivery.secret must be whsec_ followed by base64 of 24 to 64 bytes");
276
+ }
277
+ const { event, subscriber, args, id, url } = await this.resolve(params, ctx);
278
+ const ttl = params.ttlMs === null ? MAX_TTL_MS : (params.ttlMs ?? DEFAULT_TTL_MS);
279
+ const subscription = {
280
+ id,
281
+ url,
282
+ secret: params.delivery.secret,
283
+ expiresAt: new Date(Date.now() + Math.min(Math.max(ttl, MIN_TTL_MS), MAX_TTL_MS)),
284
+ };
285
+ await verifyCallback(subscriber, subscription);
286
+ await event.hooks.onSubscribe(args, { subscription, extra: ctx });
287
+ return {
288
+ id,
289
+ refreshBefore: subscription.expiresAt.toISOString(),
290
+ cursor: null,
291
+ truncated: false,
292
+ };
293
+ });
294
+ this.server.setRequestHandler("events/unsubscribe", { params: SubscriptionKeySchema }, async (params, ctx) => {
295
+ const { event, args, id } = await this.resolve(params, ctx);
296
+ await event.hooks.onUnsubscribe(args, {
297
+ subscription: { id },
298
+ extra: ctx,
299
+ });
300
+ return {};
301
+ });
302
+ }
303
+ async resolve(params, ctx) {
304
+ const event = this.events.get(params.name);
305
+ if (!event) {
306
+ throw new ProtocolError(EVENTS_ERROR.NotFound, `Unknown event: ${params.name}`, { kind: "event" });
307
+ }
308
+ const url = checkCallbackUrl(params.delivery.url);
309
+ const subscriber = subscriberOf(ctx);
310
+ const rawArguments = params.arguments ?? {};
311
+ const args = await validate(event.inputSchema, rawArguments);
312
+ const hash = createHash("sha256")
313
+ .update(canonicalJson([subscriber, url, event.name, rawArguments]))
314
+ .digest("hex");
315
+ return { event, subscriber, args, url, id: `sub_${hash.slice(0, 32)}` };
316
+ }
317
+ }
318
+ //# sourceMappingURL=events.js.map