@frontmcp/sdk 0.4.1 → 0.5.0

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 (558) hide show
  1. package/README.md +30 -18
  2. package/package.json +20 -5
  3. package/src/app/app.registry.d.ts +3 -2
  4. package/src/app/app.registry.js +3 -1
  5. package/src/app/app.registry.js.map +1 -1
  6. package/src/app/instances/app.local.instance.js +2 -2
  7. package/src/app/instances/app.local.instance.js.map +1 -1
  8. package/src/auth/auth.registry.d.ts +34 -2
  9. package/src/auth/auth.registry.js +162 -24
  10. package/src/auth/auth.registry.js.map +1 -1
  11. package/src/auth/auth.utils.js +8 -9
  12. package/src/auth/auth.utils.js.map +1 -1
  13. package/src/auth/authorization/authorization.class.d.ts +125 -0
  14. package/src/auth/authorization/authorization.class.js +224 -0
  15. package/src/auth/authorization/authorization.class.js.map +1 -0
  16. package/src/auth/authorization/authorization.types.d.ts +300 -0
  17. package/src/auth/authorization/authorization.types.js +79 -0
  18. package/src/auth/authorization/authorization.types.js.map +1 -0
  19. package/src/auth/authorization/index.d.ts +5 -0
  20. package/src/auth/authorization/index.js +19 -0
  21. package/src/auth/authorization/index.js.map +1 -0
  22. package/src/auth/authorization/orchestrated.authorization.d.ts +242 -0
  23. package/src/auth/authorization/orchestrated.authorization.js +306 -0
  24. package/src/auth/authorization/orchestrated.authorization.js.map +1 -0
  25. package/src/auth/authorization/public.authorization.d.ts +91 -0
  26. package/src/auth/authorization/public.authorization.js +132 -0
  27. package/src/auth/authorization/public.authorization.js.map +1 -0
  28. package/src/auth/authorization/transparent.authorization.d.ts +130 -0
  29. package/src/auth/authorization/transparent.authorization.js +147 -0
  30. package/src/auth/authorization/transparent.authorization.js.map +1 -0
  31. package/src/auth/consent/consent.types.d.ts +111 -0
  32. package/src/auth/consent/consent.types.js +119 -0
  33. package/src/auth/consent/consent.types.js.map +1 -0
  34. package/src/auth/consent/index.d.ts +1 -0
  35. package/src/auth/consent/index.js +13 -0
  36. package/src/auth/consent/index.js.map +1 -0
  37. package/src/auth/detection/auth-provider-detection.d.ts +84 -0
  38. package/src/auth/detection/auth-provider-detection.js +230 -0
  39. package/src/auth/detection/auth-provider-detection.js.map +1 -0
  40. package/src/auth/detection/index.d.ts +1 -0
  41. package/src/auth/detection/index.js +15 -0
  42. package/src/auth/detection/index.js.map +1 -0
  43. package/src/auth/flows/auth.verify.flow.d.ts +110 -0
  44. package/src/auth/flows/auth.verify.flow.js +379 -0
  45. package/src/auth/flows/auth.verify.flow.js.map +1 -0
  46. package/src/auth/flows/oauth.authorize.flow.d.ts +118 -164
  47. package/src/auth/flows/oauth.authorize.flow.js +701 -33
  48. package/src/auth/flows/oauth.authorize.flow.js.map +1 -1
  49. package/src/auth/flows/oauth.callback.flow.d.ts +117 -0
  50. package/src/auth/flows/oauth.callback.flow.js +357 -0
  51. package/src/auth/flows/oauth.callback.flow.js.map +1 -0
  52. package/src/auth/flows/oauth.register.flow.d.ts +32 -125
  53. package/src/auth/flows/oauth.token.flow.d.ts +52 -154
  54. package/src/auth/flows/oauth.token.flow.js +193 -55
  55. package/src/auth/flows/oauth.token.flow.js.map +1 -1
  56. package/src/auth/flows/session.verify.flow.d.ts +66 -321
  57. package/src/auth/flows/session.verify.flow.js +107 -18
  58. package/src/auth/flows/session.verify.flow.js.map +1 -1
  59. package/src/auth/flows/well-known.jwks.flow.d.ts +34 -205
  60. package/src/auth/flows/well-known.jwks.flow.js +15 -8
  61. package/src/auth/flows/well-known.jwks.flow.js.map +1 -1
  62. package/src/auth/flows/well-known.oauth-authorization-server.flow.d.ts +48 -223
  63. package/src/auth/flows/well-known.oauth-authorization-server.flow.js +2 -3
  64. package/src/auth/flows/well-known.oauth-authorization-server.flow.js.map +1 -1
  65. package/src/auth/flows/well-known.prm.flow.d.ts +19 -120
  66. package/src/auth/flows/well-known.prm.flow.js +3 -4
  67. package/src/auth/flows/well-known.prm.flow.js.map +1 -1
  68. package/src/auth/instances/instance.local-primary-auth.d.ts +91 -4
  69. package/src/auth/instances/instance.local-primary-auth.js +236 -6
  70. package/src/auth/instances/instance.local-primary-auth.js.map +1 -1
  71. package/src/auth/instances/instance.remote-primary-auth.d.ts +4 -3
  72. package/src/auth/instances/instance.remote-primary-auth.js +2 -2
  73. package/src/auth/instances/instance.remote-primary-auth.js.map +1 -1
  74. package/src/auth/session/authorization-vault.d.ts +611 -0
  75. package/src/auth/session/authorization-vault.js +817 -0
  76. package/src/auth/session/authorization-vault.js.map +1 -0
  77. package/src/auth/session/authorization.store.d.ts +301 -0
  78. package/src/auth/session/authorization.store.js +323 -0
  79. package/src/auth/session/authorization.store.js.map +1 -0
  80. package/src/auth/session/encrypted-authorization-vault.d.ts +181 -0
  81. package/src/auth/session/encrypted-authorization-vault.js +493 -0
  82. package/src/auth/session/encrypted-authorization-vault.js.map +1 -0
  83. package/src/auth/session/index.d.ts +4 -4
  84. package/src/auth/session/index.js +11 -7
  85. package/src/auth/session/index.js.map +1 -1
  86. package/src/auth/session/session.schema.d.ts +1 -1
  87. package/src/auth/session/session.service.d.ts +1 -1
  88. package/src/auth/session/transport-session.manager.d.ts +101 -0
  89. package/src/auth/session/transport-session.manager.js +300 -0
  90. package/src/auth/session/transport-session.manager.js.map +1 -0
  91. package/src/auth/session/transport-session.types.d.ts +457 -0
  92. package/src/auth/session/transport-session.types.js +110 -0
  93. package/src/auth/session/transport-session.types.js.map +1 -0
  94. package/src/auth/session/utils/session-id.utils.d.ts +14 -2
  95. package/src/auth/session/utils/session-id.utils.js +68 -19
  96. package/src/auth/session/utils/session-id.utils.js.map +1 -1
  97. package/src/auth/session/vault-encryption.d.ts +189 -0
  98. package/src/auth/session/vault-encryption.js +263 -0
  99. package/src/auth/session/vault-encryption.js.map +1 -0
  100. package/src/auth/ui/base-layout.d.ts +188 -0
  101. package/src/auth/ui/base-layout.js +292 -0
  102. package/src/auth/ui/base-layout.js.map +1 -0
  103. package/src/auth/ui/htmx-templates.d.ts +135 -0
  104. package/src/auth/ui/htmx-templates.js +433 -0
  105. package/src/auth/ui/htmx-templates.js.map +1 -0
  106. package/src/auth/ui/index.d.ts +11 -0
  107. package/src/auth/ui/index.js +35 -0
  108. package/src/auth/ui/index.js.map +1 -0
  109. package/src/auth/utils/audience.validator.d.ts +129 -0
  110. package/src/auth/utils/audience.validator.js +196 -0
  111. package/src/auth/utils/audience.validator.js.map +1 -0
  112. package/src/auth/utils/index.d.ts +2 -0
  113. package/src/auth/utils/index.js +7 -0
  114. package/src/auth/utils/index.js.map +1 -0
  115. package/src/auth/utils/www-authenticate.utils.d.ts +97 -0
  116. package/src/auth/utils/www-authenticate.utils.js +183 -0
  117. package/src/auth/utils/www-authenticate.utils.js.map +1 -0
  118. package/src/common/common.schema.d.ts +2 -16
  119. package/src/common/constants.d.ts +3 -0
  120. package/src/common/constants.js +6 -1
  121. package/src/common/constants.js.map +1 -1
  122. package/src/common/decorators/decorator-utils.d.ts +131 -0
  123. package/src/common/decorators/decorator-utils.js +195 -0
  124. package/src/common/decorators/decorator-utils.js.map +1 -0
  125. package/src/common/decorators/front-mcp.decorator.js +3 -2
  126. package/src/common/decorators/front-mcp.decorator.js.map +1 -1
  127. package/src/common/decorators/hook.decorator.d.ts +58 -2
  128. package/src/common/decorators/hook.decorator.js +127 -17
  129. package/src/common/decorators/hook.decorator.js.map +1 -1
  130. package/src/common/decorators/plugin.decorator.d.ts +1 -1
  131. package/src/common/decorators/plugin.decorator.js +11 -10
  132. package/src/common/decorators/plugin.decorator.js.map +1 -1
  133. package/src/common/decorators/resource.decorator.d.ts +32 -3
  134. package/src/common/decorators/resource.decorator.js +46 -4
  135. package/src/common/decorators/resource.decorator.js.map +1 -1
  136. package/src/common/decorators/tool.decorator.d.ts +54 -5
  137. package/src/common/decorators/tool.decorator.js.map +1 -1
  138. package/src/common/dynamic/dynamic.plugin.d.ts +22 -11
  139. package/src/common/dynamic/dynamic.plugin.js +7 -1
  140. package/src/common/dynamic/dynamic.plugin.js.map +1 -1
  141. package/src/common/entries/prompt.entry.d.ts +46 -2
  142. package/src/common/entries/prompt.entry.js +10 -0
  143. package/src/common/entries/prompt.entry.js.map +1 -1
  144. package/src/common/entries/resource.entry.d.ts +69 -6
  145. package/src/common/entries/resource.entry.js +27 -3
  146. package/src/common/entries/resource.entry.js.map +1 -1
  147. package/src/common/entries/scope.entry.d.ts +5 -1
  148. package/src/common/entries/scope.entry.js +3 -3
  149. package/src/common/entries/scope.entry.js.map +1 -1
  150. package/src/common/flow/flow.utils.d.ts +56 -0
  151. package/src/common/flow/flow.utils.js +96 -0
  152. package/src/common/flow/flow.utils.js.map +1 -0
  153. package/src/common/index.d.ts +2 -2
  154. package/src/common/index.js +2 -2
  155. package/src/common/index.js.map +1 -1
  156. package/src/common/interfaces/execution-context.interface.d.ts +59 -0
  157. package/src/common/interfaces/execution-context.interface.js +81 -0
  158. package/src/common/interfaces/execution-context.interface.js.map +1 -0
  159. package/src/common/interfaces/flow.interface.d.ts +1 -1
  160. package/src/common/interfaces/flow.interface.js.map +1 -1
  161. package/src/common/interfaces/index.d.ts +1 -0
  162. package/src/common/interfaces/index.js +1 -0
  163. package/src/common/interfaces/index.js.map +1 -1
  164. package/src/common/interfaces/internal/primary-auth-provider.interface.d.ts +17 -2
  165. package/src/common/interfaces/internal/primary-auth-provider.interface.js +52 -4
  166. package/src/common/interfaces/internal/primary-auth-provider.interface.js.map +1 -1
  167. package/src/common/interfaces/internal/registry.interface.d.ts +16 -2
  168. package/src/common/interfaces/internal/registry.interface.js.map +1 -1
  169. package/src/common/interfaces/plugin.interface.js.map +1 -1
  170. package/src/common/interfaces/prompt.interface.d.ts +53 -4
  171. package/src/common/interfaces/prompt.interface.js +78 -0
  172. package/src/common/interfaces/prompt.interface.js.map +1 -1
  173. package/src/common/interfaces/resource.interface.d.ts +47 -17
  174. package/src/common/interfaces/resource.interface.js +53 -0
  175. package/src/common/interfaces/resource.interface.js.map +1 -1
  176. package/src/common/interfaces/tool.interface.d.ts +39 -22
  177. package/src/common/interfaces/tool.interface.js +61 -34
  178. package/src/common/interfaces/tool.interface.js.map +1 -1
  179. package/src/common/metadata/adapter.metadata.d.ts +1 -9
  180. package/src/common/metadata/app.metadata.d.ts +425 -730
  181. package/src/common/metadata/auth-provider.metadata.d.ts +2 -12
  182. package/src/common/metadata/flow.metadata.d.ts +10 -25
  183. package/src/common/metadata/front-mcp.metadata.d.ts +602 -1023
  184. package/src/common/metadata/front-mcp.metadata.js +6 -4
  185. package/src/common/metadata/front-mcp.metadata.js.map +1 -1
  186. package/src/common/metadata/hook.metadata.d.ts +1 -1
  187. package/src/common/metadata/hook.metadata.js.map +1 -1
  188. package/src/common/metadata/index.d.ts +1 -0
  189. package/src/common/metadata/index.js +1 -0
  190. package/src/common/metadata/index.js.map +1 -1
  191. package/src/common/metadata/logger.metadata.d.ts +1 -9
  192. package/src/common/metadata/plugin.metadata.d.ts +8 -30
  193. package/src/common/metadata/prompt.metadata.d.ts +4 -161
  194. package/src/common/metadata/provider.metadata.d.ts +2 -12
  195. package/src/common/metadata/resource.metadata.d.ts +6 -98
  196. package/src/common/metadata/resource.metadata.js +15 -6
  197. package/src/common/metadata/resource.metadata.js.map +1 -1
  198. package/src/common/metadata/tool-ui.metadata.d.ts +10 -0
  199. package/src/common/metadata/tool-ui.metadata.js +12 -0
  200. package/src/common/metadata/tool-ui.metadata.js.map +1 -0
  201. package/src/common/metadata/tool.metadata.d.ts +78 -199
  202. package/src/common/metadata/tool.metadata.js +11 -14
  203. package/src/common/metadata/tool.metadata.js.map +1 -1
  204. package/src/common/providers/base-config.provider.d.ts +84 -0
  205. package/src/common/providers/base-config.provider.js +128 -0
  206. package/src/common/providers/base-config.provider.js.map +1 -0
  207. package/src/common/records/plugin.record.d.ts +5 -6
  208. package/src/common/records/plugin.record.js.map +1 -1
  209. package/src/common/records/prompt.record.js.map +1 -1
  210. package/src/common/records/resource.record.d.ts +17 -1
  211. package/src/common/records/resource.record.js +12 -6
  212. package/src/common/records/resource.record.js.map +1 -1
  213. package/src/common/records/tool.record.js.map +1 -1
  214. package/src/common/schemas/annotated-class.schema.d.ts +9 -9
  215. package/src/common/schemas/annotated-class.schema.js +92 -27
  216. package/src/common/schemas/annotated-class.schema.js.map +1 -1
  217. package/src/common/schemas/http-input.schema.d.ts +6 -30
  218. package/src/common/schemas/http-output.schema.d.ts +326 -1630
  219. package/src/common/schemas/http-output.schema.js +39 -1
  220. package/src/common/schemas/http-output.schema.js.map +1 -1
  221. package/src/common/tokens/front-mcp.tokens.js +4 -1
  222. package/src/common/tokens/front-mcp.tokens.js.map +1 -1
  223. package/src/common/tokens/resource.tokens.d.ts +2 -0
  224. package/src/common/tokens/resource.tokens.js +4 -1
  225. package/src/common/tokens/resource.tokens.js.map +1 -1
  226. package/src/common/tokens/tool.tokens.d.ts +2 -0
  227. package/src/common/tokens/tool.tokens.js +2 -0
  228. package/src/common/tokens/tool.tokens.js.map +1 -1
  229. package/src/common/types/auth/jwt.types.d.ts +5 -31
  230. package/src/common/types/auth/session.types.d.ts +97 -192
  231. package/src/common/types/auth/session.types.js +24 -11
  232. package/src/common/types/auth/session.types.js.map +1 -1
  233. package/src/common/types/options/auth.options.d.ts +1013 -490
  234. package/src/common/types/options/auth.options.js +554 -36
  235. package/src/common/types/options/auth.options.js.map +1 -1
  236. package/src/common/types/options/http.options.d.ts +1 -9
  237. package/src/common/types/options/logging.options.d.ts +7 -13
  238. package/src/common/types/options/logging.options.js +4 -0
  239. package/src/common/types/options/logging.options.js.map +1 -1
  240. package/src/common/types/options/server-info.options.d.ts +3 -31
  241. package/src/common/types/options/session.options.d.ts +90 -10
  242. package/src/common/types/options/session.options.js +26 -3
  243. package/src/common/types/options/session.options.js.map +1 -1
  244. package/src/common/utils/decide-request-intent.utils.d.ts +8 -46
  245. package/src/common/utils/decide-request-intent.utils.js +88 -23
  246. package/src/common/utils/decide-request-intent.utils.js.map +1 -1
  247. package/src/completion/flows/complete.flow.d.ts +74 -0
  248. package/src/completion/flows/complete.flow.js +199 -0
  249. package/src/completion/flows/complete.flow.js.map +1 -0
  250. package/src/errors/authorization-required.error.d.ts +189 -0
  251. package/src/errors/authorization-required.error.js +274 -0
  252. package/src/errors/authorization-required.error.js.map +1 -0
  253. package/src/errors/index.d.ts +2 -1
  254. package/src/errors/index.js +17 -1
  255. package/src/errors/index.js.map +1 -1
  256. package/src/errors/mcp.error.d.ts +101 -1
  257. package/src/errors/mcp.error.js +147 -2
  258. package/src/errors/mcp.error.js.map +1 -1
  259. package/src/flows/flow.instance.js +4 -3
  260. package/src/flows/flow.instance.js.map +1 -1
  261. package/src/flows/flow.registry.js.map +1 -1
  262. package/src/flows/flow.stages.js +14 -11
  263. package/src/flows/flow.stages.js.map +1 -1
  264. package/src/front-mcp/front-mcp.providers.d.ts +464 -102
  265. package/src/front-mcp/front-mcp.providers.js +3 -5
  266. package/src/front-mcp/front-mcp.providers.js.map +1 -1
  267. package/src/hooks/hook.instance.d.ts +1 -1
  268. package/src/hooks/hook.instance.js +5 -2
  269. package/src/hooks/hook.instance.js.map +1 -1
  270. package/src/hooks/hook.registry.js +7 -5
  271. package/src/hooks/hook.registry.js.map +1 -1
  272. package/src/index.d.ts +28 -9
  273. package/src/index.js +5 -1
  274. package/src/index.js.map +1 -1
  275. package/src/logger/instances/instance.logger.js +3 -2
  276. package/src/logger/instances/instance.logger.js.map +1 -1
  277. package/src/logger/logger.registry.js +7 -2
  278. package/src/logger/logger.registry.js.map +1 -1
  279. package/src/logging/flows/set-level.flow.d.ts +62 -0
  280. package/src/logging/flows/set-level.flow.js +108 -0
  281. package/src/logging/flows/set-level.flow.js.map +1 -0
  282. package/src/mcp-apps/csp.d.ts +111 -0
  283. package/src/mcp-apps/csp.js +267 -0
  284. package/src/mcp-apps/csp.js.map +1 -0
  285. package/src/mcp-apps/index.d.ts +23 -0
  286. package/src/mcp-apps/index.js +91 -0
  287. package/src/mcp-apps/index.js.map +1 -0
  288. package/src/mcp-apps/schemas.d.ts +403 -0
  289. package/src/mcp-apps/schemas.js +345 -0
  290. package/src/mcp-apps/schemas.js.map +1 -0
  291. package/src/mcp-apps/template.d.ts +94 -0
  292. package/src/mcp-apps/template.js +419 -0
  293. package/src/mcp-apps/template.js.map +1 -0
  294. package/src/mcp-apps/types.d.ts +323 -0
  295. package/src/mcp-apps/types.js +59 -0
  296. package/src/mcp-apps/types.js.map +1 -0
  297. package/src/notification/index.d.ts +1 -0
  298. package/src/notification/index.js +13 -0
  299. package/src/notification/index.js.map +1 -0
  300. package/src/notification/notification.service.d.ts +378 -0
  301. package/src/notification/notification.service.js +727 -0
  302. package/src/notification/notification.service.js.map +1 -0
  303. package/src/plugin/plugin.registry.js +12 -9
  304. package/src/plugin/plugin.registry.js.map +1 -1
  305. package/src/prompt/flows/get-prompt.flow.d.ts +153 -0
  306. package/src/prompt/flows/get-prompt.flow.js +214 -0
  307. package/src/prompt/flows/get-prompt.flow.js.map +1 -0
  308. package/src/prompt/flows/prompts-list.flow.d.ts +67 -0
  309. package/src/prompt/flows/prompts-list.flow.js +176 -0
  310. package/src/prompt/flows/prompts-list.flow.js.map +1 -0
  311. package/src/prompt/index.d.ts +7 -0
  312. package/src/prompt/index.js +17 -0
  313. package/src/prompt/index.js.map +1 -0
  314. package/src/prompt/prompt.events.d.ts +17 -0
  315. package/src/prompt/prompt.events.js +25 -0
  316. package/src/prompt/prompt.events.js.map +1 -0
  317. package/src/prompt/prompt.instance.d.ts +30 -0
  318. package/src/prompt/prompt.instance.js +120 -0
  319. package/src/prompt/prompt.instance.js.map +1 -0
  320. package/src/prompt/prompt.registry.d.ts +79 -12
  321. package/src/prompt/prompt.registry.js +360 -15
  322. package/src/prompt/prompt.registry.js.map +1 -1
  323. package/src/prompt/prompt.types.d.ts +26 -0
  324. package/src/prompt/prompt.types.js +11 -0
  325. package/src/prompt/prompt.types.js.map +1 -0
  326. package/src/prompt/prompt.utils.d.ts +26 -0
  327. package/src/prompt/prompt.utils.js +136 -0
  328. package/src/prompt/prompt.utils.js.map +1 -0
  329. package/src/provider/provider.registry.d.ts +12 -5
  330. package/src/provider/provider.registry.js +30 -138
  331. package/src/provider/provider.registry.js.map +1 -1
  332. package/src/regsitry/registry.base.d.ts +1 -1
  333. package/src/regsitry/registry.base.js.map +1 -1
  334. package/src/resource/flows/read-resource.flow.d.ts +91 -0
  335. package/src/resource/flows/read-resource.flow.js +270 -0
  336. package/src/resource/flows/read-resource.flow.js.map +1 -0
  337. package/src/resource/flows/resource-templates-list.flow.d.ts +64 -0
  338. package/src/resource/flows/resource-templates-list.flow.js +191 -0
  339. package/src/resource/flows/resource-templates-list.flow.js.map +1 -0
  340. package/src/resource/flows/resources-list.flow.d.ts +64 -0
  341. package/src/resource/flows/resources-list.flow.js +196 -0
  342. package/src/resource/flows/resources-list.flow.js.map +1 -0
  343. package/src/resource/flows/subscribe-resource.flow.d.ts +45 -0
  344. package/src/resource/flows/subscribe-resource.flow.js +123 -0
  345. package/src/resource/flows/subscribe-resource.flow.js.map +1 -0
  346. package/src/resource/flows/unsubscribe-resource.flow.d.ts +44 -0
  347. package/src/resource/flows/unsubscribe-resource.flow.js +107 -0
  348. package/src/resource/flows/unsubscribe-resource.flow.js.map +1 -0
  349. package/src/resource/index.d.ts +8 -0
  350. package/src/resource/index.js +20 -0
  351. package/src/resource/index.js.map +1 -0
  352. package/src/resource/resource.events.d.ts +24 -0
  353. package/src/resource/resource.events.js +17 -0
  354. package/src/resource/resource.events.js.map +1 -0
  355. package/src/resource/resource.instance.d.ts +35 -0
  356. package/src/resource/resource.instance.js +163 -0
  357. package/src/resource/resource.instance.js.map +1 -0
  358. package/src/resource/resource.registry.d.ts +106 -12
  359. package/src/resource/resource.registry.js +449 -13
  360. package/src/resource/resource.registry.js.map +1 -1
  361. package/src/resource/resource.types.d.ts +35 -0
  362. package/src/resource/resource.types.js +11 -0
  363. package/src/resource/resource.types.js.map +1 -0
  364. package/src/resource/resource.utils.d.ts +30 -0
  365. package/src/resource/resource.utils.js +151 -0
  366. package/src/resource/resource.utils.js.map +1 -0
  367. package/src/scope/flows/http.request.flow.d.ts +48 -330
  368. package/src/scope/flows/http.request.flow.js +306 -78
  369. package/src/scope/flows/http.request.flow.js.map +1 -1
  370. package/src/scope/scope.instance.d.ts +12 -0
  371. package/src/scope/scope.instance.js +145 -15
  372. package/src/scope/scope.instance.js.map +1 -1
  373. package/src/tool/flows/call-tool.flow.d.ts +64 -1110
  374. package/src/tool/flows/call-tool.flow.js +303 -15
  375. package/src/tool/flows/call-tool.flow.js.map +1 -1
  376. package/src/tool/flows/tools-list.flow.d.ts +32 -473
  377. package/src/tool/flows/tools-list.flow.js +121 -40
  378. package/src/tool/flows/tools-list.flow.js.map +1 -1
  379. package/src/tool/tool.events.d.ts +8 -1
  380. package/src/tool/tool.events.js.map +1 -1
  381. package/src/tool/tool.instance.d.ts +3 -1
  382. package/src/tool/tool.instance.js +17 -3
  383. package/src/tool/tool.instance.js.map +1 -1
  384. package/src/tool/tool.registry.d.ts +7 -1
  385. package/src/tool/tool.registry.js +26 -10
  386. package/src/tool/tool.registry.js.map +1 -1
  387. package/src/tool/tool.types.d.ts +4 -4
  388. package/src/tool/tool.types.js.map +1 -1
  389. package/src/tool/tool.utils.d.ts +3 -12
  390. package/src/tool/tool.utils.js +39 -193
  391. package/src/tool/tool.utils.js.map +1 -1
  392. package/src/tool/ui/index.d.ts +22 -0
  393. package/src/tool/ui/index.js +63 -0
  394. package/src/tool/ui/index.js.map +1 -0
  395. package/src/tool/ui/platform-adapters.d.ts +10 -0
  396. package/src/tool/ui/platform-adapters.js +18 -0
  397. package/src/tool/ui/platform-adapters.js.map +1 -0
  398. package/src/tool/ui/template-helpers.d.ts +46 -0
  399. package/src/tool/ui/template-helpers.js +112 -0
  400. package/src/tool/ui/template-helpers.js.map +1 -0
  401. package/src/tool/ui/ui-resource-template.d.ts +34 -0
  402. package/src/tool/ui/ui-resource-template.js +64 -0
  403. package/src/tool/ui/ui-resource-template.js.map +1 -0
  404. package/src/tool/ui/ui-resource.handler.d.ts +74 -0
  405. package/src/tool/ui/ui-resource.handler.js +129 -0
  406. package/src/tool/ui/ui-resource.handler.js.map +1 -0
  407. package/src/transport/adapters/transport.local.adapter.d.ts +2 -2
  408. package/src/transport/adapters/transport.local.adapter.js +28 -7
  409. package/src/transport/adapters/transport.local.adapter.js.map +1 -1
  410. package/src/transport/adapters/transport.sse.adapter.d.ts +2 -2
  411. package/src/transport/adapters/transport.sse.adapter.js +4 -3
  412. package/src/transport/adapters/transport.sse.adapter.js.map +1 -1
  413. package/src/transport/adapters/transport.streamable-http.adapter.d.ts +10 -3
  414. package/src/transport/adapters/transport.streamable-http.adapter.js +54 -8
  415. package/src/transport/adapters/transport.streamable-http.adapter.js.map +1 -1
  416. package/src/transport/flows/handle.sse.flow.d.ts +29 -63
  417. package/src/transport/flows/handle.sse.flow.js +78 -10
  418. package/src/transport/flows/handle.sse.flow.js.map +1 -1
  419. package/src/transport/flows/handle.stateless-http.flow.d.ts +29 -0
  420. package/src/transport/flows/handle.stateless-http.flow.js +102 -0
  421. package/src/transport/flows/handle.stateless-http.flow.js.map +1 -0
  422. package/src/transport/flows/handle.streamable-http.flow.d.ts +32 -64
  423. package/src/transport/flows/handle.streamable-http.flow.js +158 -26
  424. package/src/transport/flows/handle.streamable-http.flow.js.map +1 -1
  425. package/src/transport/legacy/legacy.sse.tranporter.d.ts +9 -0
  426. package/src/transport/legacy/legacy.sse.tranporter.js +17 -2
  427. package/src/transport/legacy/legacy.sse.tranporter.js.map +1 -1
  428. package/src/transport/mcp-handlers/call-tool-request.handler.js +27 -1
  429. package/src/transport/mcp-handlers/call-tool-request.handler.js.map +1 -1
  430. package/src/transport/mcp-handlers/complete-request.handler.d.ts +69 -0
  431. package/src/transport/mcp-handlers/complete-request.handler.js +11 -0
  432. package/src/transport/mcp-handlers/complete-request.handler.js.map +1 -0
  433. package/src/transport/mcp-handlers/get-prompt-request.handler.d.ts +87 -0
  434. package/src/transport/mcp-handlers/get-prompt-request.handler.js +11 -0
  435. package/src/transport/mcp-handlers/get-prompt-request.handler.js.map +1 -0
  436. package/src/transport/mcp-handlers/index.d.ts +517 -208
  437. package/src/transport/mcp-handlers/index.js +39 -2
  438. package/src/transport/mcp-handlers/index.js.map +1 -1
  439. package/src/transport/mcp-handlers/initialize-request.handler.d.ts +1 -1
  440. package/src/transport/mcp-handlers/initialize-request.handler.js +73 -7
  441. package/src/transport/mcp-handlers/initialize-request.handler.js.map +1 -1
  442. package/src/transport/mcp-handlers/list-prompts-request.handler.d.ts +54 -0
  443. package/src/transport/mcp-handlers/list-prompts-request.handler.js +11 -0
  444. package/src/transport/mcp-handlers/list-prompts-request.handler.js.map +1 -0
  445. package/src/transport/mcp-handlers/list-resource-templates-request.handler.d.ts +51 -0
  446. package/src/transport/mcp-handlers/list-resource-templates-request.handler.js +12 -0
  447. package/src/transport/mcp-handlers/list-resource-templates-request.handler.js.map +1 -0
  448. package/src/transport/mcp-handlers/list-resources-request.handler.d.ts +51 -0
  449. package/src/transport/mcp-handlers/list-resources-request.handler.js +12 -0
  450. package/src/transport/mcp-handlers/list-resources-request.handler.js.map +1 -0
  451. package/src/transport/mcp-handlers/list-tools-request.handler.d.ts +19 -146
  452. package/src/transport/mcp-handlers/logging-set-level-request.handler.d.ts +46 -0
  453. package/src/transport/mcp-handlers/logging-set-level-request.handler.js +34 -0
  454. package/src/transport/mcp-handlers/logging-set-level-request.handler.js.map +1 -0
  455. package/src/transport/mcp-handlers/mcp-handlers.types.d.ts +3 -7
  456. package/src/transport/mcp-handlers/mcp-handlers.types.js.map +1 -1
  457. package/src/transport/mcp-handlers/read-resource-request.handler.d.ts +46 -0
  458. package/src/transport/mcp-handlers/read-resource-request.handler.js +12 -0
  459. package/src/transport/mcp-handlers/read-resource-request.handler.js.map +1 -0
  460. package/src/transport/mcp-handlers/roots-list-changed-notification.handler.d.ts +11 -0
  461. package/src/transport/mcp-handlers/roots-list-changed-notification.handler.js +26 -0
  462. package/src/transport/mcp-handlers/roots-list-changed-notification.handler.js.map +1 -0
  463. package/src/transport/mcp-handlers/subscribe-request.handler.d.ts +37 -0
  464. package/src/transport/mcp-handlers/subscribe-request.handler.js +34 -0
  465. package/src/transport/mcp-handlers/subscribe-request.handler.js.map +1 -0
  466. package/src/transport/mcp-handlers/unsubscribe-request.handler.d.ts +37 -0
  467. package/src/transport/mcp-handlers/unsubscribe-request.handler.js +34 -0
  468. package/src/transport/mcp-handlers/unsubscribe-request.handler.js.map +1 -0
  469. package/src/transport/transport.local.js +7 -2
  470. package/src/transport/transport.local.js.map +1 -1
  471. package/src/transport/transport.registry.d.ts +30 -0
  472. package/src/transport/transport.registry.js +84 -1
  473. package/src/transport/transport.registry.js.map +1 -1
  474. package/src/transport/transport.types.d.ts +3 -3
  475. package/src/transport/transport.types.js.map +1 -1
  476. package/src/utils/content.utils.d.ts +48 -0
  477. package/src/utils/content.utils.js +194 -0
  478. package/src/utils/content.utils.js.map +1 -0
  479. package/src/utils/index.d.ts +8 -0
  480. package/src/utils/index.js +55 -0
  481. package/src/utils/index.js.map +1 -0
  482. package/src/utils/lineage.utils.d.ts +40 -0
  483. package/src/utils/lineage.utils.js +82 -0
  484. package/src/utils/lineage.utils.js.map +1 -0
  485. package/src/utils/naming.utils.d.ts +46 -0
  486. package/src/utils/naming.utils.js +136 -0
  487. package/src/utils/naming.utils.js.map +1 -0
  488. package/src/utils/types.utils.d.ts +2 -2
  489. package/src/utils/types.utils.js.map +1 -1
  490. package/src/utils/uri-template.utils.d.ts +57 -0
  491. package/src/utils/uri-template.utils.js +113 -0
  492. package/src/utils/uri-template.utils.js.map +1 -0
  493. package/src/utils/uri-validation.utils.d.ts +40 -0
  494. package/src/utils/uri-validation.utils.js +76 -0
  495. package/src/utils/uri-validation.utils.js.map +1 -0
  496. package/src/__test-utils__/fixtures/hook.fixtures.d.ts +0 -46
  497. package/src/__test-utils__/fixtures/hook.fixtures.js +0 -114
  498. package/src/__test-utils__/fixtures/hook.fixtures.js.map +0 -1
  499. package/src/__test-utils__/fixtures/index.d.ts +0 -7
  500. package/src/__test-utils__/fixtures/index.js +0 -11
  501. package/src/__test-utils__/fixtures/index.js.map +0 -1
  502. package/src/__test-utils__/fixtures/plugin.fixtures.d.ts +0 -46
  503. package/src/__test-utils__/fixtures/plugin.fixtures.js +0 -127
  504. package/src/__test-utils__/fixtures/plugin.fixtures.js.map +0 -1
  505. package/src/__test-utils__/fixtures/provider.fixtures.d.ts +0 -69
  506. package/src/__test-utils__/fixtures/provider.fixtures.js +0 -131
  507. package/src/__test-utils__/fixtures/provider.fixtures.js.map +0 -1
  508. package/src/__test-utils__/fixtures/scope.fixtures.d.ts +0 -14
  509. package/src/__test-utils__/fixtures/scope.fixtures.js +0 -59
  510. package/src/__test-utils__/fixtures/scope.fixtures.js.map +0 -1
  511. package/src/__test-utils__/fixtures/tool.fixtures.d.ts +0 -36
  512. package/src/__test-utils__/fixtures/tool.fixtures.js +0 -91
  513. package/src/__test-utils__/fixtures/tool.fixtures.js.map +0 -1
  514. package/src/__test-utils__/helpers/assertion.helpers.d.ts +0 -45
  515. package/src/__test-utils__/helpers/assertion.helpers.js +0 -153
  516. package/src/__test-utils__/helpers/assertion.helpers.js.map +0 -1
  517. package/src/__test-utils__/helpers/async.helpers.d.ts +0 -48
  518. package/src/__test-utils__/helpers/async.helpers.js +0 -112
  519. package/src/__test-utils__/helpers/async.helpers.js.map +0 -1
  520. package/src/__test-utils__/helpers/index.d.ts +0 -6
  521. package/src/__test-utils__/helpers/index.js +0 -10
  522. package/src/__test-utils__/helpers/index.js.map +0 -1
  523. package/src/__test-utils__/helpers/setup.helpers.d.ts +0 -54
  524. package/src/__test-utils__/helpers/setup.helpers.js +0 -106
  525. package/src/__test-utils__/helpers/setup.helpers.js.map +0 -1
  526. package/src/__test-utils__/index.d.ts +0 -9
  527. package/src/__test-utils__/index.js +0 -14
  528. package/src/__test-utils__/index.js.map +0 -1
  529. package/src/__test-utils__/mocks/flow-instance.mock.d.ts +0 -50
  530. package/src/__test-utils__/mocks/flow-instance.mock.js +0 -72
  531. package/src/__test-utils__/mocks/flow-instance.mock.js.map +0 -1
  532. package/src/__test-utils__/mocks/hook-registry.mock.d.ts +0 -25
  533. package/src/__test-utils__/mocks/hook-registry.mock.js +0 -65
  534. package/src/__test-utils__/mocks/hook-registry.mock.js.map +0 -1
  535. package/src/__test-utils__/mocks/index.d.ts +0 -8
  536. package/src/__test-utils__/mocks/index.js +0 -12
  537. package/src/__test-utils__/mocks/index.js.map +0 -1
  538. package/src/__test-utils__/mocks/plugin-registry.mock.d.ts +0 -43
  539. package/src/__test-utils__/mocks/plugin-registry.mock.js +0 -70
  540. package/src/__test-utils__/mocks/plugin-registry.mock.js.map +0 -1
  541. package/src/__test-utils__/mocks/provider-registry.mock.d.ts +0 -39
  542. package/src/__test-utils__/mocks/provider-registry.mock.js +0 -72
  543. package/src/__test-utils__/mocks/provider-registry.mock.js.map +0 -1
  544. package/src/__test-utils__/mocks/tool-registry.mock.d.ts +0 -43
  545. package/src/__test-utils__/mocks/tool-registry.mock.js +0 -79
  546. package/src/__test-utils__/mocks/tool-registry.mock.js.map +0 -1
  547. package/src/auth/path.utils.d.ts +0 -20
  548. package/src/auth/path.utils.js +0 -71
  549. package/src/auth/path.utils.js.map +0 -1
  550. package/src/common/decorators-old/async-with.decorator.d.ts +0 -10
  551. package/src/common/decorators-old/async-with.decorator.js +0 -24
  552. package/src/common/decorators-old/async-with.decorator.js.map +0 -1
  553. package/src/common/decorators-old/auth-hook.decorator.d.ts +0 -14
  554. package/src/common/decorators-old/auth-hook.decorator.js +0 -27
  555. package/src/common/decorators-old/auth-hook.decorator.js.map +0 -1
  556. package/src/common/decorators-old/session-hook.decorator.d.ts +0 -14
  557. package/src/common/decorators-old/session-hook.decorator.js +0 -27
  558. package/src/common/decorators-old/session-hook.decorator.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.encryptJson = encryptJson;
4
+ exports.decryptPublicSession = decryptPublicSession;
4
5
  exports.parseSessionHeader = parseSessionHeader;
5
6
  exports.createSessionId = createSessionId;
6
7
  exports.generateSessionCookie = generateSessionCookie;
@@ -9,6 +10,7 @@ exports.extractSessionFromCookie = extractSessionFromCookie;
9
10
  const crypto_1 = require("crypto");
10
11
  const tiny_ttl_cache_1 = require("./tiny-ttl-cache");
11
12
  const auth_token_utils_1 = require("./auth-token.utils");
13
+ const notification_service_1 = require("../../../notification/notification.service");
12
14
  // 5s TTL cache for decrypted headers
13
15
  const cache = new tiny_ttl_cache_1.TinyTtlCache(5000);
14
16
  // Single-process machine id generated at server launch
@@ -39,27 +41,64 @@ function encryptJson(obj) {
39
41
  // Pack iv.tag.ct as base64url(iv.tag.ct)
40
42
  return `${b64urlEncode(iv)}.${b64urlEncode(tag)}.${b64urlEncode(ct)}`;
41
43
  }
42
- function decryptSessionId(sessionId, sig) {
43
- const key = getKey();
44
- const [ivB64, tagB64, ctB64] = sessionId.split('.');
44
+ /**
45
+ * Low-level decryption that returns the raw JSON payload or null.
46
+ * Handles all crypto/parsing failures by returning null.
47
+ */
48
+ function decryptSessionJson(sessionId) {
49
+ const parts = sessionId.split('.');
50
+ if (parts.length !== 3)
51
+ return null;
52
+ const [ivB64, tagB64, ctB64] = parts;
45
53
  if (!ivB64 || !tagB64 || !ctB64)
46
54
  return null;
55
+ const key = getKey();
56
+ const iv = b64urlDecode(ivB64);
57
+ const tag = b64urlDecode(tagB64);
58
+ const ct = b64urlDecode(ctB64);
59
+ const decipher = (0, crypto_1.createDecipheriv)('aes-256-gcm', key, iv);
60
+ decipher.setAuthTag(tag);
61
+ const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
62
+ return JSON.parse(pt.toString('utf8'));
63
+ }
64
+ function isValidSessionPayload(dec, sig) {
65
+ if (typeof dec !== 'object' || dec === null)
66
+ return false;
67
+ const d = dec;
68
+ return (typeof d['nodeId'] === 'string' &&
69
+ typeof d['authSig'] === 'string' &&
70
+ typeof d['uuid'] === 'string' &&
71
+ typeof d['iat'] === 'number' &&
72
+ d['authSig'] === sig);
73
+ }
74
+ function isValidPublicSessionPayload(dec) {
75
+ if (typeof dec !== 'object' || dec === null)
76
+ return false;
77
+ const d = dec;
78
+ return (typeof d['nodeId'] === 'string' &&
79
+ d['authSig'] === 'public' &&
80
+ typeof d['uuid'] === 'string' &&
81
+ typeof d['iat'] === 'number' &&
82
+ d['isPublic'] === true);
83
+ }
84
+ function decryptSessionId(sessionId, sig) {
85
+ const dec = safeDecrypt(sessionId);
86
+ return isValidSessionPayload(dec, sig) ? dec : null;
87
+ }
88
+ /**
89
+ * Decrypt a public session ID without signature verification.
90
+ * Public sessions use authSig: 'public' and isPublic: true
91
+ */
92
+ function decryptPublicSession(sessionId) {
93
+ const dec = safeDecrypt(sessionId);
94
+ return isValidPublicSessionPayload(dec) ? dec : null;
95
+ }
96
+ /**
97
+ * Safe wrapper around decryptSessionJson that catches crypto/parse errors.
98
+ */
99
+ function safeDecrypt(sessionId) {
47
100
  try {
48
- const iv = b64urlDecode(ivB64);
49
- const tag = b64urlDecode(tagB64);
50
- const ct = b64urlDecode(ctB64);
51
- const decipher = (0, crypto_1.createDecipheriv)('aes-256-gcm', key, iv);
52
- decipher.setAuthTag(tag);
53
- const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
54
- const dec = JSON.parse(pt.toString('utf8'));
55
- if (typeof dec.nodeId === 'string' &&
56
- typeof dec.authSig === 'string' &&
57
- typeof dec.uuid === 'string' &&
58
- typeof dec.iat === 'number' &&
59
- dec.authSig === sig) {
60
- return dec;
61
- }
62
- throw new Error('Invalid session id');
101
+ return decryptSessionJson(sessionId);
63
102
  }
64
103
  catch {
65
104
  return null;
@@ -103,14 +142,24 @@ function parseSessionHeader(sessionHeader, token) {
103
142
  // cache.set(headerSse, decodedSse);
104
143
  // return { header, decoded, headerSse, isNew: true };
105
144
  }
106
- function createSessionId(protocol, token) {
145
+ function createSessionId(protocol, token, options) {
107
146
  const authSig = (0, auth_token_utils_1.getTokenSignatureFingerprint)(token);
147
+ // Detect platform from user-agent if provided (before MCP initialize)
148
+ let platformType;
149
+ if (options?.userAgent) {
150
+ platformType = (0, notification_service_1.detectPlatformFromUserAgent)(options.userAgent, options.platformDetectionConfig);
151
+ // Only set if we detected something meaningful
152
+ if (platformType === 'unknown') {
153
+ platformType = undefined;
154
+ }
155
+ }
108
156
  const payload = {
109
157
  nodeId: MACHINE_ID,
110
158
  authSig,
111
159
  uuid: (0, crypto_1.randomUUID)(),
112
160
  iat: nowSec(),
113
161
  protocol,
162
+ platformType,
114
163
  };
115
164
  const id = encryptJson(payload);
116
165
  cache.set(id, payload);
@@ -1 +1 @@
1
- {"version":3,"file":"session-id.utils.js","sourceRoot":"","sources":["../../../../../src/auth/session/utils/session-id.utils.ts"],"names":[],"mappings":"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","sourcesContent":["// auth/session/utils/session-id.utils.ts\nimport { randomUUID, createHash, randomBytes, createCipheriv, createDecipheriv } from 'crypto';\nimport { TinyTtlCache } from './tiny-ttl-cache';\nimport { HttpRequestIntent, SessionIdPayload } from '../../../common';\nimport { getTokenSignatureFingerprint } from './auth-token.utils';\n\n// 5s TTL cache for decrypted headers\nconst cache = new TinyTtlCache<string, SessionIdPayload>(5000);\n\n// Single-process machine id generated at server launch\nconst MACHINE_ID = (() => {\n // Prefer an injected env (stable across restarts) if you have one; else random per launch:\n return process.env['MACHINE_ID'] || randomUUID(); // TODO: move to gateway config module\n})();\n\n// Symmetric key derived from secret or machine id (stable for the process)\nfunction getKey(): Buffer {\n const base = process.env['MCP_SESSION_SECRET'] || MACHINE_ID; // TODO: move to gateway config module\n return createHash('sha256').update(base).digest(); // 32 bytes\n}\n\nfunction b64urlEncode(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction b64urlDecode(s: string): Buffer {\n const pad = 4 - (s.length % 4);\n const base64 = s.replace(/-/g, '+').replace(/_/g, '/') + (pad < 4 ? '='.repeat(pad) : '');\n return Buffer.from(base64, 'base64');\n}\n\nexport function encryptJson(obj: unknown): string {\n const key = getKey();\n const iv = randomBytes(12); // AES-GCM 96-bit IV\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const pt = Buffer.from(JSON.stringify(obj), 'utf8');\n const ct = Buffer.concat([cipher.update(pt), cipher.final()]);\n const tag = cipher.getAuthTag();\n // Pack iv.tag.ct as base64url(iv.tag.ct)\n return `${b64urlEncode(iv)}.${b64urlEncode(tag)}.${b64urlEncode(ct)}`;\n}\n\nfunction decryptSessionId(sessionId: string, sig: string): SessionIdPayload | null {\n const key = getKey();\n const [ivB64, tagB64, ctB64] = sessionId.split('.');\n if (!ivB64 || !tagB64 || !ctB64) return null;\n try {\n const iv = b64urlDecode(ivB64);\n const tag = b64urlDecode(tagB64);\n const ct = b64urlDecode(ctB64);\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n const pt = Buffer.concat([decipher.update(ct), decipher.final()]);\n const dec = JSON.parse(pt.toString('utf8'));\n if (\n typeof dec.nodeId === 'string' &&\n typeof dec.authSig === 'string' &&\n typeof dec.uuid === 'string' &&\n typeof dec.iat === 'number' &&\n dec.authSig === sig\n ) {\n return dec;\n }\n\n throw new Error('Invalid session id');\n } catch {\n return null;\n }\n}\n\nfunction nowSec(): number {\n return Math.floor(Date.now() / 1000);\n}\n\n/**\n * Validates an existing session header OR creates a fresh one.\n * - Valid: nodeId matches local, authSig matches current Authorization\n * - On any mismatch/decrypt error → generate new\n */\nexport function parseSessionHeader(\n sessionHeader: string | undefined,\n token: string,\n): { id: string; payload: SessionIdPayload } | undefined {\n const currentAuthSig = getTokenSignatureFingerprint(token);\n if (sessionHeader) {\n const cached = cache.get(sessionHeader);\n if (cached) {\n if (cached.authSig === currentAuthSig) {\n return { id: sessionHeader, payload: cached };\n }\n // fallthrough to regenerate if mismatch\n }\n\n const dec = decryptSessionId(sessionHeader, currentAuthSig);\n if (dec) {\n cache.set(sessionHeader, dec);\n return { id: sessionHeader, payload: dec as SessionIdPayload };\n }\n }\n\n return undefined;\n // // Create fresh\n\n // const decodedSse: SessionIdPayload = {\n // nodeId: MACHINE_ID,\n // authSig: currentAuthSig,\n // uuid: randomUUID(),\n // iat: nowSec(),\n // };\n // const header = encryptJson(decoded);\n // const headerSse = encryptJson(decodedSse);\n // cache.set(header, decoded);\n // cache.set(headerSse, decodedSse);\n // return { header, decoded, headerSse, isNew: true };\n}\n\nexport function createSessionId(protocol: HttpRequestIntent, token: string) {\n const authSig = getTokenSignatureFingerprint(token);\n const payload: SessionIdPayload = {\n nodeId: MACHINE_ID,\n authSig,\n uuid: randomUUID(),\n iat: nowSec(),\n protocol,\n };\n const id = encryptJson(payload);\n cache.set(id, payload);\n return { id, payload };\n}\n\nexport function generateSessionCookie(sessionId: string, ttlInMinutes = 60 * 24): string {\n const expires = new Date(Date.now() + ttlInMinutes * 60 * 1000).toUTCString();\n return `mcp_session_id=${sessionId}; Path=/; Expires=${expires}; HttpOnly; SameSite=Lax`;\n}\n\nexport function extractSessionFromCookie(cookie?: string): string | undefined {\n if (!cookie) return undefined;\n const m = cookie.match(/(^|;)\\s*mcp_session_id\\s*=\\s*([^;]*)/);\n return m ? m[2] : undefined;\n}\n\n\n"]}
1
+ {"version":3,"file":"session-id.utils.js","sourceRoot":"","sources":["../../../../../src/auth/session/utils/session-id.utils.ts"],"names":[],"mappings":"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","sourcesContent":["// auth/session/utils/session-id.utils.ts\nimport { randomUUID, createHash, randomBytes, createCipheriv, createDecipheriv } from 'crypto';\nimport { TinyTtlCache } from './tiny-ttl-cache';\nimport { SessionIdPayload, TransportProtocolType, AIPlatformType } from '../../../common';\nimport { getTokenSignatureFingerprint } from './auth-token.utils';\nimport { detectPlatformFromUserAgent } from '../../../notification/notification.service';\nimport type { PlatformDetectionConfig } from '../../../common/types/options/session.options';\n\n// 5s TTL cache for decrypted headers\nconst cache = new TinyTtlCache<string, SessionIdPayload>(5000);\n\n// Single-process machine id generated at server launch\nconst MACHINE_ID = (() => {\n // Prefer an injected env (stable across restarts) if you have one; else random per launch:\n return process.env['MACHINE_ID'] || randomUUID(); // TODO: move to gateway config module\n})();\n\n// Symmetric key derived from secret or machine id (stable for the process)\nfunction getKey(): Buffer {\n const base = process.env['MCP_SESSION_SECRET'] || MACHINE_ID; // TODO: move to gateway config module\n return createHash('sha256').update(base).digest(); // 32 bytes\n}\n\nfunction b64urlEncode(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction b64urlDecode(s: string): Buffer {\n const pad = 4 - (s.length % 4);\n const base64 = s.replace(/-/g, '+').replace(/_/g, '/') + (pad < 4 ? '='.repeat(pad) : '');\n return Buffer.from(base64, 'base64');\n}\n\nexport function encryptJson(obj: unknown): string {\n const key = getKey();\n const iv = randomBytes(12); // AES-GCM 96-bit IV\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const pt = Buffer.from(JSON.stringify(obj), 'utf8');\n const ct = Buffer.concat([cipher.update(pt), cipher.final()]);\n const tag = cipher.getAuthTag();\n // Pack iv.tag.ct as base64url(iv.tag.ct)\n return `${b64urlEncode(iv)}.${b64urlEncode(tag)}.${b64urlEncode(ct)}`;\n}\n\n/**\n * Low-level decryption that returns the raw JSON payload or null.\n * Handles all crypto/parsing failures by returning null.\n */\nfunction decryptSessionJson(sessionId: string): unknown {\n const parts = sessionId.split('.');\n if (parts.length !== 3) return null;\n\n const [ivB64, tagB64, ctB64] = parts;\n if (!ivB64 || !tagB64 || !ctB64) return null;\n\n const key = getKey();\n const iv = b64urlDecode(ivB64);\n const tag = b64urlDecode(tagB64);\n const ct = b64urlDecode(ctB64);\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n const pt = Buffer.concat([decipher.update(ct), decipher.final()]);\n return JSON.parse(pt.toString('utf8'));\n}\n\nfunction isValidSessionPayload(dec: unknown, sig: string): dec is SessionIdPayload {\n if (typeof dec !== 'object' || dec === null) return false;\n const d = dec as Record<string, unknown>;\n return (\n typeof d['nodeId'] === 'string' &&\n typeof d['authSig'] === 'string' &&\n typeof d['uuid'] === 'string' &&\n typeof d['iat'] === 'number' &&\n d['authSig'] === sig\n );\n}\n\nfunction isValidPublicSessionPayload(dec: unknown): dec is SessionIdPayload {\n if (typeof dec !== 'object' || dec === null) return false;\n const d = dec as Record<string, unknown>;\n return (\n typeof d['nodeId'] === 'string' &&\n d['authSig'] === 'public' &&\n typeof d['uuid'] === 'string' &&\n typeof d['iat'] === 'number' &&\n d['isPublic'] === true\n );\n}\n\nfunction decryptSessionId(sessionId: string, sig: string): SessionIdPayload | null {\n const dec = safeDecrypt(sessionId);\n return isValidSessionPayload(dec, sig) ? dec : null;\n}\n\n/**\n * Decrypt a public session ID without signature verification.\n * Public sessions use authSig: 'public' and isPublic: true\n */\nexport function decryptPublicSession(sessionId: string): SessionIdPayload | null {\n const dec = safeDecrypt(sessionId);\n return isValidPublicSessionPayload(dec) ? dec : null;\n}\n\n/**\n * Safe wrapper around decryptSessionJson that catches crypto/parse errors.\n */\nfunction safeDecrypt(sessionId: string): unknown {\n try {\n return decryptSessionJson(sessionId);\n } catch {\n return null;\n }\n}\n\nfunction nowSec(): number {\n return Math.floor(Date.now() / 1000);\n}\n\n/**\n * Validates an existing session header OR creates a fresh one.\n * - Valid: nodeId matches local, authSig matches current Authorization\n * - On any mismatch/decrypt error → generate new\n */\nexport function parseSessionHeader(\n sessionHeader: string | undefined,\n token: string,\n): { id: string; payload: SessionIdPayload } | undefined {\n const currentAuthSig = getTokenSignatureFingerprint(token);\n if (sessionHeader) {\n const cached = cache.get(sessionHeader);\n if (cached) {\n if (cached.authSig === currentAuthSig) {\n return { id: sessionHeader, payload: cached };\n }\n // fallthrough to regenerate if mismatch\n }\n\n const dec = decryptSessionId(sessionHeader, currentAuthSig);\n if (dec) {\n cache.set(sessionHeader, dec);\n return { id: sessionHeader, payload: dec as SessionIdPayload };\n }\n }\n\n return undefined;\n // // Create fresh\n\n // const decodedSse: SessionIdPayload = {\n // nodeId: MACHINE_ID,\n // authSig: currentAuthSig,\n // uuid: randomUUID(),\n // iat: nowSec(),\n // };\n // const header = encryptJson(decoded);\n // const headerSse = encryptJson(decodedSse);\n // cache.set(header, decoded);\n // cache.set(headerSse, decodedSse);\n // return { header, decoded, headerSse, isNew: true };\n}\n\nexport interface CreateSessionOptions {\n /** User-Agent header for pre-initialize platform detection */\n userAgent?: string;\n /** Platform detection configuration from scope */\n platformDetectionConfig?: PlatformDetectionConfig;\n}\n\nexport function createSessionId(protocol: TransportProtocolType, token: string, options?: CreateSessionOptions) {\n const authSig = getTokenSignatureFingerprint(token);\n\n // Detect platform from user-agent if provided (before MCP initialize)\n let platformType: AIPlatformType | undefined;\n if (options?.userAgent) {\n platformType = detectPlatformFromUserAgent(options.userAgent, options.platformDetectionConfig);\n // Only set if we detected something meaningful\n if (platformType === 'unknown') {\n platformType = undefined;\n }\n }\n\n const payload: SessionIdPayload = {\n nodeId: MACHINE_ID,\n authSig,\n uuid: randomUUID(),\n iat: nowSec(),\n protocol,\n platformType,\n };\n const id = encryptJson(payload);\n cache.set(id, payload);\n return { id, payload };\n}\n\nexport function generateSessionCookie(sessionId: string, ttlInMinutes = 60 * 24): string {\n const expires = new Date(Date.now() + ttlInMinutes * 60 * 1000).toUTCString();\n return `mcp_session_id=${sessionId}; Path=/; Expires=${expires}; HttpOnly; SameSite=Lax`;\n}\n\nexport function extractSessionFromCookie(cookie?: string): string | undefined {\n if (!cookie) return undefined;\n const m = cookie.match(/(^|;)\\s*mcp_session_id\\s*=\\s*([^;]*)/);\n return m ? m[2] : undefined;\n}\n"]}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Vault Encryption
3
+ *
4
+ * Client-side key derivation for zero-knowledge credential storage.
5
+ *
6
+ * Security Model:
7
+ * - The JWT authorization token contains a unique `jti` (JWT ID) claim
8
+ * - A secret portion of the token (or a derived key) is used as the encryption key
9
+ * - The server stores encrypted blobs in Redis but CANNOT decrypt them
10
+ * - Only the client presenting the valid JWT can decrypt their vault
11
+ *
12
+ * Key Derivation:
13
+ * - Input: JWT token (after signature verification)
14
+ * - Extract: jti + a secret claim (e.g., `vaultKey` or derived from signature)
15
+ * - Derive: HKDF-SHA256 to produce AES-256 key
16
+ *
17
+ * Encryption:
18
+ * - Algorithm: AES-256-GCM (authenticated encryption)
19
+ * - IV: Random 12 bytes per encryption (stored with ciphertext)
20
+ * - Auth Tag: 16 bytes (ensures integrity)
21
+ */
22
+ import { z } from 'zod';
23
+ /**
24
+ * Encrypted data format stored in Redis
25
+ */
26
+ export declare const encryptedDataSchema: z.ZodObject<{
27
+ v: z.ZodLiteral<1>;
28
+ alg: z.ZodLiteral<"aes-256-gcm">;
29
+ iv: z.ZodString;
30
+ ct: z.ZodString;
31
+ tag: z.ZodString;
32
+ }, z.core.$strip>;
33
+ export type EncryptedData = z.infer<typeof encryptedDataSchema>;
34
+ /**
35
+ * JWT claims required for key derivation
36
+ */
37
+ export interface VaultKeyDerivationClaims {
38
+ /** JWT ID - unique identifier for this token/vault */
39
+ jti: string;
40
+ /** Vault key material - secret claim added during token generation */
41
+ vaultKey?: string;
42
+ /** Subject - user identifier */
43
+ sub: string;
44
+ /** Issued at timestamp */
45
+ iat: number;
46
+ }
47
+ /**
48
+ * Vault encryption configuration
49
+ */
50
+ export interface VaultEncryptionConfig {
51
+ /**
52
+ * Server-side pepper added to key derivation
53
+ * This adds defense-in-depth: even with a stolen JWT,
54
+ * attacker needs the pepper to derive the key
55
+ */
56
+ pepper?: string;
57
+ /**
58
+ * Key derivation info string for HKDF
59
+ * Allows domain separation between different uses
60
+ */
61
+ hkdfInfo?: string;
62
+ }
63
+ /**
64
+ * VaultEncryption handles encryption/decryption of vault credentials
65
+ * using keys derived from the client's JWT authorization token.
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * const encryption = new VaultEncryption({ pepper: process.env.VAULT_PEPPER });
70
+ *
71
+ * // After JWT verification, derive the encryption key
72
+ * const key = encryption.deriveKey(jwtClaims);
73
+ *
74
+ * // Encrypt credentials before storing
75
+ * const encrypted = encryption.encrypt(JSON.stringify(credentials), key);
76
+ *
77
+ * // Decrypt when reading
78
+ * const decrypted = encryption.decrypt(encrypted, key);
79
+ * const credentials = JSON.parse(decrypted);
80
+ * ```
81
+ */
82
+ export declare class VaultEncryption {
83
+ private readonly pepper;
84
+ private readonly hkdfInfo;
85
+ constructor(config?: VaultEncryptionConfig);
86
+ /**
87
+ * Derive an encryption key from JWT claims
88
+ *
89
+ * The key derivation uses HKDF-like construction:
90
+ * 1. Combine jti + vaultKey + sub + iat + pepper
91
+ * 2. Apply HMAC-SHA256 to derive a 256-bit key
92
+ *
93
+ * @param claims - JWT claims containing key material
94
+ * @returns 32-byte encryption key
95
+ */
96
+ deriveKey(claims: VaultKeyDerivationClaims): Buffer;
97
+ /**
98
+ * Derive a key directly from the raw JWT token string
99
+ *
100
+ * This is useful when you want to derive the key from the token
101
+ * before or without fully parsing the claims. Uses the token's
102
+ * signature portion as additional entropy.
103
+ *
104
+ * @param token - The raw JWT token string
105
+ * @param claims - Parsed JWT claims
106
+ * @returns 32-byte encryption key
107
+ */
108
+ deriveKeyFromToken(token: string, claims: VaultKeyDerivationClaims): Buffer;
109
+ /**
110
+ * Encrypt plaintext data using AES-256-GCM
111
+ *
112
+ * @param plaintext - Data to encrypt (typically JSON string)
113
+ * @param key - 32-byte encryption key from deriveKey()
114
+ * @returns Encrypted data object (safe to store in Redis)
115
+ */
116
+ encrypt(plaintext: string, key: Buffer): EncryptedData;
117
+ /**
118
+ * Decrypt encrypted data using AES-256-GCM
119
+ *
120
+ * @param encrypted - Encrypted data object from encrypt()
121
+ * @param key - 32-byte encryption key from deriveKey()
122
+ * @returns Decrypted plaintext
123
+ * @throws Error if decryption fails (wrong key, tampered data, etc.)
124
+ */
125
+ decrypt(encrypted: EncryptedData, key: Buffer): string;
126
+ /**
127
+ * Encrypt a JavaScript object (serializes to JSON first)
128
+ *
129
+ * @param data - Object to encrypt
130
+ * @param key - Encryption key
131
+ * @returns Encrypted data
132
+ */
133
+ encryptObject<T>(data: T, key: Buffer): EncryptedData;
134
+ /**
135
+ * Decrypt and parse a JavaScript object
136
+ *
137
+ * @param encrypted - Encrypted data
138
+ * @param key - Encryption key
139
+ * @returns Decrypted and parsed object
140
+ */
141
+ decryptObject<T>(encrypted: EncryptedData, key: Buffer): T;
142
+ /**
143
+ * Check if data is in encrypted format
144
+ *
145
+ * @param data - Data to check
146
+ * @returns True if data appears to be encrypted
147
+ */
148
+ isEncrypted(data: unknown): data is EncryptedData;
149
+ }
150
+ /**
151
+ * Vault entry with encrypted credentials
152
+ *
153
+ * The structure separates:
154
+ * - Metadata (unencrypted): id, userSub, timestamps, app lists
155
+ * - Sensitive data (encrypted): provider tokens, app credentials
156
+ */
157
+ export declare const encryptedVaultEntrySchema: z.ZodObject<{
158
+ id: z.ZodString;
159
+ userSub: z.ZodString;
160
+ userEmail: z.ZodOptional<z.ZodString>;
161
+ userName: z.ZodOptional<z.ZodString>;
162
+ clientId: z.ZodString;
163
+ createdAt: z.ZodNumber;
164
+ lastAccessAt: z.ZodNumber;
165
+ encryptedData: z.ZodObject<{
166
+ v: z.ZodLiteral<1>;
167
+ alg: z.ZodLiteral<"aes-256-gcm">;
168
+ iv: z.ZodString;
169
+ ct: z.ZodString;
170
+ tag: z.ZodString;
171
+ }, z.core.$strip>;
172
+ authorizedAppIds: z.ZodArray<z.ZodString>;
173
+ skippedAppIds: z.ZodArray<z.ZodString>;
174
+ pendingAuthIds: z.ZodDefault<z.ZodArray<z.ZodString>>;
175
+ }, z.core.$strip>;
176
+ export type EncryptedVaultEntry = z.infer<typeof encryptedVaultEntrySchema>;
177
+ /**
178
+ * Sensitive data that gets encrypted
179
+ */
180
+ export interface VaultSensitiveData {
181
+ /** App credentials */
182
+ appCredentials: Record<string, unknown>;
183
+ /** Consent record */
184
+ consent?: unknown;
185
+ /** Federated login record */
186
+ federated?: unknown;
187
+ /** Pending auth details (URLs, scopes, etc.) */
188
+ pendingAuths: unknown[];
189
+ }
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ /**
3
+ * Vault Encryption
4
+ *
5
+ * Client-side key derivation for zero-knowledge credential storage.
6
+ *
7
+ * Security Model:
8
+ * - The JWT authorization token contains a unique `jti` (JWT ID) claim
9
+ * - A secret portion of the token (or a derived key) is used as the encryption key
10
+ * - The server stores encrypted blobs in Redis but CANNOT decrypt them
11
+ * - Only the client presenting the valid JWT can decrypt their vault
12
+ *
13
+ * Key Derivation:
14
+ * - Input: JWT token (after signature verification)
15
+ * - Extract: jti + a secret claim (e.g., `vaultKey` or derived from signature)
16
+ * - Derive: HKDF-SHA256 to produce AES-256 key
17
+ *
18
+ * Encryption:
19
+ * - Algorithm: AES-256-GCM (authenticated encryption)
20
+ * - IV: Random 12 bytes per encryption (stored with ciphertext)
21
+ * - Auth Tag: 16 bytes (ensures integrity)
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.encryptedVaultEntrySchema = exports.VaultEncryption = exports.encryptedDataSchema = void 0;
25
+ const node_crypto_1 = require("node:crypto");
26
+ const zod_1 = require("zod");
27
+ // ============================================
28
+ // Types and Schemas
29
+ // ============================================
30
+ /**
31
+ * Encrypted data format stored in Redis
32
+ */
33
+ exports.encryptedDataSchema = zod_1.z.object({
34
+ /** Version for future algorithm changes */
35
+ v: zod_1.z.literal(1),
36
+ /** Algorithm identifier */
37
+ alg: zod_1.z.literal('aes-256-gcm'),
38
+ /** Initialization vector (base64) */
39
+ iv: zod_1.z.string(),
40
+ /** Ciphertext (base64) */
41
+ ct: zod_1.z.string(),
42
+ /** Authentication tag (base64) */
43
+ tag: zod_1.z.string(),
44
+ });
45
+ // ============================================
46
+ // Vault Encryption Class
47
+ // ============================================
48
+ /**
49
+ * VaultEncryption handles encryption/decryption of vault credentials
50
+ * using keys derived from the client's JWT authorization token.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const encryption = new VaultEncryption({ pepper: process.env.VAULT_PEPPER });
55
+ *
56
+ * // After JWT verification, derive the encryption key
57
+ * const key = encryption.deriveKey(jwtClaims);
58
+ *
59
+ * // Encrypt credentials before storing
60
+ * const encrypted = encryption.encrypt(JSON.stringify(credentials), key);
61
+ *
62
+ * // Decrypt when reading
63
+ * const decrypted = encryption.decrypt(encrypted, key);
64
+ * const credentials = JSON.parse(decrypted);
65
+ * ```
66
+ */
67
+ class VaultEncryption {
68
+ pepper;
69
+ hkdfInfo;
70
+ constructor(config = {}) {
71
+ // Convert pepper to buffer, use empty if not provided
72
+ this.pepper = Buffer.from(config.pepper ?? '', 'utf8');
73
+ this.hkdfInfo = Buffer.from(config.hkdfInfo ?? 'frontmcp-vault-v1', 'utf8');
74
+ }
75
+ /**
76
+ * Derive an encryption key from JWT claims
77
+ *
78
+ * The key derivation uses HKDF-like construction:
79
+ * 1. Combine jti + vaultKey + sub + iat + pepper
80
+ * 2. Apply HMAC-SHA256 to derive a 256-bit key
81
+ *
82
+ * @param claims - JWT claims containing key material
83
+ * @returns 32-byte encryption key
84
+ */
85
+ deriveKey(claims) {
86
+ // Build the input key material (IKM)
87
+ // Using multiple claims ensures the key is unique per token
88
+ const ikm = Buffer.concat([
89
+ Buffer.from(claims.jti, 'utf8'),
90
+ Buffer.from(claims.vaultKey ?? '', 'utf8'),
91
+ Buffer.from(claims.sub, 'utf8'),
92
+ Buffer.from(claims.iat.toString(), 'utf8'),
93
+ this.pepper,
94
+ ]);
95
+ // HKDF-Extract: PRK = HMAC-SHA256(salt, IKM)
96
+ // Using hkdfInfo as salt for domain separation
97
+ const prk = (0, node_crypto_1.createHmac)('sha256', this.hkdfInfo).update(ikm).digest();
98
+ // HKDF-Expand: OKM = HMAC-SHA256(PRK, info || 0x01)
99
+ // We only need 32 bytes, so single iteration is sufficient
100
+ const okm = (0, node_crypto_1.createHmac)('sha256', prk)
101
+ .update(Buffer.concat([this.hkdfInfo, Buffer.from([0x01])]))
102
+ .digest();
103
+ return okm;
104
+ }
105
+ /**
106
+ * Derive a key directly from the raw JWT token string
107
+ *
108
+ * This is useful when you want to derive the key from the token
109
+ * before or without fully parsing the claims. Uses the token's
110
+ * signature portion as additional entropy.
111
+ *
112
+ * @param token - The raw JWT token string
113
+ * @param claims - Parsed JWT claims
114
+ * @returns 32-byte encryption key
115
+ */
116
+ deriveKeyFromToken(token, claims) {
117
+ // Extract signature from JWT (last part after final dot)
118
+ const parts = token.split('.');
119
+ const signature = parts[2] ?? '';
120
+ // Include signature in key derivation for additional entropy
121
+ const ikm = Buffer.concat([
122
+ Buffer.from(claims.jti, 'utf8'),
123
+ Buffer.from(claims.vaultKey ?? '', 'utf8'),
124
+ Buffer.from(claims.sub, 'utf8'),
125
+ Buffer.from(claims.iat.toString(), 'utf8'),
126
+ Buffer.from(signature, 'utf8'),
127
+ this.pepper,
128
+ ]);
129
+ const prk = (0, node_crypto_1.createHmac)('sha256', this.hkdfInfo).update(ikm).digest();
130
+ const okm = (0, node_crypto_1.createHmac)('sha256', prk)
131
+ .update(Buffer.concat([this.hkdfInfo, Buffer.from([0x01])]))
132
+ .digest();
133
+ return okm;
134
+ }
135
+ /**
136
+ * Encrypt plaintext data using AES-256-GCM
137
+ *
138
+ * @param plaintext - Data to encrypt (typically JSON string)
139
+ * @param key - 32-byte encryption key from deriveKey()
140
+ * @returns Encrypted data object (safe to store in Redis)
141
+ */
142
+ encrypt(plaintext, key) {
143
+ if (key.length !== 32) {
144
+ throw new Error('Encryption key must be 32 bytes');
145
+ }
146
+ // Generate random 12-byte IV (recommended for GCM)
147
+ const iv = (0, node_crypto_1.randomBytes)(12);
148
+ // Create cipher
149
+ const cipher = (0, node_crypto_1.createCipheriv)('aes-256-gcm', key, iv);
150
+ // Encrypt
151
+ const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
152
+ // Get authentication tag
153
+ const tag = cipher.getAuthTag();
154
+ return {
155
+ v: 1,
156
+ alg: 'aes-256-gcm',
157
+ iv: iv.toString('base64'),
158
+ ct: ciphertext.toString('base64'),
159
+ tag: tag.toString('base64'),
160
+ };
161
+ }
162
+ /**
163
+ * Decrypt encrypted data using AES-256-GCM
164
+ *
165
+ * @param encrypted - Encrypted data object from encrypt()
166
+ * @param key - 32-byte encryption key from deriveKey()
167
+ * @returns Decrypted plaintext
168
+ * @throws Error if decryption fails (wrong key, tampered data, etc.)
169
+ */
170
+ decrypt(encrypted, key) {
171
+ if (key.length !== 32) {
172
+ throw new Error('Encryption key must be 32 bytes');
173
+ }
174
+ // Validate encrypted data format
175
+ const parsed = exports.encryptedDataSchema.safeParse(encrypted);
176
+ if (!parsed.success) {
177
+ throw new Error('Invalid encrypted data format');
178
+ }
179
+ const { iv, ct, tag } = parsed.data;
180
+ // Decode from base64
181
+ const ivBuffer = Buffer.from(iv, 'base64');
182
+ const ciphertext = Buffer.from(ct, 'base64');
183
+ const tagBuffer = Buffer.from(tag, 'base64');
184
+ // Create decipher
185
+ const decipher = (0, node_crypto_1.createDecipheriv)('aes-256-gcm', key, ivBuffer);
186
+ decipher.setAuthTag(tagBuffer);
187
+ // Decrypt
188
+ try {
189
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
190
+ return plaintext.toString('utf8');
191
+ }
192
+ catch (error) {
193
+ // GCM authentication failed - wrong key or tampered data
194
+ throw new Error('Decryption failed: invalid key or corrupted data');
195
+ }
196
+ }
197
+ /**
198
+ * Encrypt a JavaScript object (serializes to JSON first)
199
+ *
200
+ * @param data - Object to encrypt
201
+ * @param key - Encryption key
202
+ * @returns Encrypted data
203
+ */
204
+ encryptObject(data, key) {
205
+ return this.encrypt(JSON.stringify(data), key);
206
+ }
207
+ /**
208
+ * Decrypt and parse a JavaScript object
209
+ *
210
+ * @param encrypted - Encrypted data
211
+ * @param key - Encryption key
212
+ * @returns Decrypted and parsed object
213
+ */
214
+ decryptObject(encrypted, key) {
215
+ const plaintext = this.decrypt(encrypted, key);
216
+ return JSON.parse(plaintext);
217
+ }
218
+ /**
219
+ * Check if data is in encrypted format
220
+ *
221
+ * @param data - Data to check
222
+ * @returns True if data appears to be encrypted
223
+ */
224
+ isEncrypted(data) {
225
+ return exports.encryptedDataSchema.safeParse(data).success;
226
+ }
227
+ }
228
+ exports.VaultEncryption = VaultEncryption;
229
+ // ============================================
230
+ // Encrypted Vault Entry Schema
231
+ // ============================================
232
+ /**
233
+ * Vault entry with encrypted credentials
234
+ *
235
+ * The structure separates:
236
+ * - Metadata (unencrypted): id, userSub, timestamps, app lists
237
+ * - Sensitive data (encrypted): provider tokens, app credentials
238
+ */
239
+ exports.encryptedVaultEntrySchema = zod_1.z.object({
240
+ /** Vault ID (maps to JWT jti claim) */
241
+ id: zod_1.z.string(),
242
+ /** User subject identifier */
243
+ userSub: zod_1.z.string(),
244
+ /** User email (unencrypted for display) */
245
+ userEmail: zod_1.z.string().optional(),
246
+ /** User name (unencrypted for display) */
247
+ userName: zod_1.z.string().optional(),
248
+ /** Client ID that created this session */
249
+ clientId: zod_1.z.string(),
250
+ /** Creation timestamp */
251
+ createdAt: zod_1.z.number(),
252
+ /** Last access timestamp */
253
+ lastAccessAt: zod_1.z.number(),
254
+ /** Encrypted sensitive data (provider tokens, credentials, consent) */
255
+ encryptedData: exports.encryptedDataSchema,
256
+ /** Apps that are fully authorized (unencrypted for quick lookup) */
257
+ authorizedAppIds: zod_1.z.array(zod_1.z.string()),
258
+ /** Apps that were skipped (unencrypted for quick lookup) */
259
+ skippedAppIds: zod_1.z.array(zod_1.z.string()),
260
+ /** Pending auth IDs (unencrypted for lookup, actual URLs encrypted) */
261
+ pendingAuthIds: zod_1.z.array(zod_1.z.string()).default([]),
262
+ });
263
+ //# sourceMappingURL=vault-encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault-encryption.js","sourceRoot":"","sources":["../../../../src/auth/session/vault-encryption.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Vault Encryption\n *\n * Client-side key derivation for zero-knowledge credential storage.\n *\n * Security Model:\n * - The JWT authorization token contains a unique `jti` (JWT ID) claim\n * - A secret portion of the token (or a derived key) is used as the encryption key\n * - The server stores encrypted blobs in Redis but CANNOT decrypt them\n * - Only the client presenting the valid JWT can decrypt their vault\n *\n * Key Derivation:\n * - Input: JWT token (after signature verification)\n * - Extract: jti + a secret claim (e.g., `vaultKey` or derived from signature)\n * - Derive: HKDF-SHA256 to produce AES-256 key\n *\n * Encryption:\n * - Algorithm: AES-256-GCM (authenticated encryption)\n * - IV: Random 12 bytes per encryption (stored with ciphertext)\n * - Auth Tag: 16 bytes (ensures integrity)\n */\n\nimport { createCipheriv, createDecipheriv, randomBytes, createHmac } from 'node:crypto';\nimport { z } from 'zod';\n\n// ============================================\n// Types and Schemas\n// ============================================\n\n/**\n * Encrypted data format stored in Redis\n */\nexport const encryptedDataSchema = z.object({\n /** Version for future algorithm changes */\n v: z.literal(1),\n /** Algorithm identifier */\n alg: z.literal('aes-256-gcm'),\n /** Initialization vector (base64) */\n iv: z.string(),\n /** Ciphertext (base64) */\n ct: z.string(),\n /** Authentication tag (base64) */\n tag: z.string(),\n});\n\nexport type EncryptedData = z.infer<typeof encryptedDataSchema>;\n\n/**\n * JWT claims required for key derivation\n */\nexport interface VaultKeyDerivationClaims {\n /** JWT ID - unique identifier for this token/vault */\n jti: string;\n /** Vault key material - secret claim added during token generation */\n vaultKey?: string;\n /** Subject - user identifier */\n sub: string;\n /** Issued at timestamp */\n iat: number;\n}\n\n/**\n * Vault encryption configuration\n */\nexport interface VaultEncryptionConfig {\n /**\n * Server-side pepper added to key derivation\n * This adds defense-in-depth: even with a stolen JWT,\n * attacker needs the pepper to derive the key\n */\n pepper?: string;\n /**\n * Key derivation info string for HKDF\n * Allows domain separation between different uses\n */\n hkdfInfo?: string;\n}\n\n// ============================================\n// Vault Encryption Class\n// ============================================\n\n/**\n * VaultEncryption handles encryption/decryption of vault credentials\n * using keys derived from the client's JWT authorization token.\n *\n * @example\n * ```typescript\n * const encryption = new VaultEncryption({ pepper: process.env.VAULT_PEPPER });\n *\n * // After JWT verification, derive the encryption key\n * const key = encryption.deriveKey(jwtClaims);\n *\n * // Encrypt credentials before storing\n * const encrypted = encryption.encrypt(JSON.stringify(credentials), key);\n *\n * // Decrypt when reading\n * const decrypted = encryption.decrypt(encrypted, key);\n * const credentials = JSON.parse(decrypted);\n * ```\n */\nexport class VaultEncryption {\n private readonly pepper: Buffer;\n private readonly hkdfInfo: Buffer;\n\n constructor(config: VaultEncryptionConfig = {}) {\n // Convert pepper to buffer, use empty if not provided\n this.pepper = Buffer.from(config.pepper ?? '', 'utf8');\n this.hkdfInfo = Buffer.from(config.hkdfInfo ?? 'frontmcp-vault-v1', 'utf8');\n }\n\n /**\n * Derive an encryption key from JWT claims\n *\n * The key derivation uses HKDF-like construction:\n * 1. Combine jti + vaultKey + sub + iat + pepper\n * 2. Apply HMAC-SHA256 to derive a 256-bit key\n *\n * @param claims - JWT claims containing key material\n * @returns 32-byte encryption key\n */\n deriveKey(claims: VaultKeyDerivationClaims): Buffer {\n // Build the input key material (IKM)\n // Using multiple claims ensures the key is unique per token\n const ikm = Buffer.concat([\n Buffer.from(claims.jti, 'utf8'),\n Buffer.from(claims.vaultKey ?? '', 'utf8'),\n Buffer.from(claims.sub, 'utf8'),\n Buffer.from(claims.iat.toString(), 'utf8'),\n this.pepper,\n ]);\n\n // HKDF-Extract: PRK = HMAC-SHA256(salt, IKM)\n // Using hkdfInfo as salt for domain separation\n const prk = createHmac('sha256', this.hkdfInfo).update(ikm).digest();\n\n // HKDF-Expand: OKM = HMAC-SHA256(PRK, info || 0x01)\n // We only need 32 bytes, so single iteration is sufficient\n const okm = createHmac('sha256', prk)\n .update(Buffer.concat([this.hkdfInfo, Buffer.from([0x01])]))\n .digest();\n\n return okm;\n }\n\n /**\n * Derive a key directly from the raw JWT token string\n *\n * This is useful when you want to derive the key from the token\n * before or without fully parsing the claims. Uses the token's\n * signature portion as additional entropy.\n *\n * @param token - The raw JWT token string\n * @param claims - Parsed JWT claims\n * @returns 32-byte encryption key\n */\n deriveKeyFromToken(token: string, claims: VaultKeyDerivationClaims): Buffer {\n // Extract signature from JWT (last part after final dot)\n const parts = token.split('.');\n const signature = parts[2] ?? '';\n\n // Include signature in key derivation for additional entropy\n const ikm = Buffer.concat([\n Buffer.from(claims.jti, 'utf8'),\n Buffer.from(claims.vaultKey ?? '', 'utf8'),\n Buffer.from(claims.sub, 'utf8'),\n Buffer.from(claims.iat.toString(), 'utf8'),\n Buffer.from(signature, 'utf8'),\n this.pepper,\n ]);\n\n const prk = createHmac('sha256', this.hkdfInfo).update(ikm).digest();\n const okm = createHmac('sha256', prk)\n .update(Buffer.concat([this.hkdfInfo, Buffer.from([0x01])]))\n .digest();\n\n return okm;\n }\n\n /**\n * Encrypt plaintext data using AES-256-GCM\n *\n * @param plaintext - Data to encrypt (typically JSON string)\n * @param key - 32-byte encryption key from deriveKey()\n * @returns Encrypted data object (safe to store in Redis)\n */\n encrypt(plaintext: string, key: Buffer): EncryptedData {\n if (key.length !== 32) {\n throw new Error('Encryption key must be 32 bytes');\n }\n\n // Generate random 12-byte IV (recommended for GCM)\n const iv = randomBytes(12);\n\n // Create cipher\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n\n // Encrypt\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n\n // Get authentication tag\n const tag = cipher.getAuthTag();\n\n return {\n v: 1,\n alg: 'aes-256-gcm',\n iv: iv.toString('base64'),\n ct: ciphertext.toString('base64'),\n tag: tag.toString('base64'),\n };\n }\n\n /**\n * Decrypt encrypted data using AES-256-GCM\n *\n * @param encrypted - Encrypted data object from encrypt()\n * @param key - 32-byte encryption key from deriveKey()\n * @returns Decrypted plaintext\n * @throws Error if decryption fails (wrong key, tampered data, etc.)\n */\n decrypt(encrypted: EncryptedData, key: Buffer): string {\n if (key.length !== 32) {\n throw new Error('Encryption key must be 32 bytes');\n }\n\n // Validate encrypted data format\n const parsed = encryptedDataSchema.safeParse(encrypted);\n if (!parsed.success) {\n throw new Error('Invalid encrypted data format');\n }\n\n const { iv, ct, tag } = parsed.data;\n\n // Decode from base64\n const ivBuffer = Buffer.from(iv, 'base64');\n const ciphertext = Buffer.from(ct, 'base64');\n const tagBuffer = Buffer.from(tag, 'base64');\n\n // Create decipher\n const decipher = createDecipheriv('aes-256-gcm', key, ivBuffer);\n decipher.setAuthTag(tagBuffer);\n\n // Decrypt\n try {\n const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n\n return plaintext.toString('utf8');\n } catch (error) {\n // GCM authentication failed - wrong key or tampered data\n throw new Error('Decryption failed: invalid key or corrupted data');\n }\n }\n\n /**\n * Encrypt a JavaScript object (serializes to JSON first)\n *\n * @param data - Object to encrypt\n * @param key - Encryption key\n * @returns Encrypted data\n */\n encryptObject<T>(data: T, key: Buffer): EncryptedData {\n return this.encrypt(JSON.stringify(data), key);\n }\n\n /**\n * Decrypt and parse a JavaScript object\n *\n * @param encrypted - Encrypted data\n * @param key - Encryption key\n * @returns Decrypted and parsed object\n */\n decryptObject<T>(encrypted: EncryptedData, key: Buffer): T {\n const plaintext = this.decrypt(encrypted, key);\n return JSON.parse(plaintext) as T;\n }\n\n /**\n * Check if data is in encrypted format\n *\n * @param data - Data to check\n * @returns True if data appears to be encrypted\n */\n isEncrypted(data: unknown): data is EncryptedData {\n return encryptedDataSchema.safeParse(data).success;\n }\n}\n\n// ============================================\n// Encrypted Vault Entry Schema\n// ============================================\n\n/**\n * Vault entry with encrypted credentials\n *\n * The structure separates:\n * - Metadata (unencrypted): id, userSub, timestamps, app lists\n * - Sensitive data (encrypted): provider tokens, app credentials\n */\nexport const encryptedVaultEntrySchema = z.object({\n /** Vault ID (maps to JWT jti claim) */\n id: z.string(),\n /** User subject identifier */\n userSub: z.string(),\n /** User email (unencrypted for display) */\n userEmail: z.string().optional(),\n /** User name (unencrypted for display) */\n userName: z.string().optional(),\n /** Client ID that created this session */\n clientId: z.string(),\n /** Creation timestamp */\n createdAt: z.number(),\n /** Last access timestamp */\n lastAccessAt: z.number(),\n /** Encrypted sensitive data (provider tokens, credentials, consent) */\n encryptedData: encryptedDataSchema,\n /** Apps that are fully authorized (unencrypted for quick lookup) */\n authorizedAppIds: z.array(z.string()),\n /** Apps that were skipped (unencrypted for quick lookup) */\n skippedAppIds: z.array(z.string()),\n /** Pending auth IDs (unencrypted for lookup, actual URLs encrypted) */\n pendingAuthIds: z.array(z.string()).default([]),\n});\n\nexport type EncryptedVaultEntry = z.infer<typeof encryptedVaultEntrySchema>;\n\n/**\n * Sensitive data that gets encrypted\n */\nexport interface VaultSensitiveData {\n /** App credentials */\n appCredentials: Record<string, unknown>;\n /** Consent record */\n consent?: unknown;\n /** Federated login record */\n federated?: unknown;\n /** Pending auth details (URLs, scopes, etc.) */\n pendingAuths: unknown[];\n}\n"]}