@toa.io/extensions.exposition 1.0.0-alpha.283 → 1.0.0-alpha.285

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 (568) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/components/exposition.octets/types/index.d.ts +1 -1
  3. package/components/identity.bans/operations/transit.js +1 -1
  4. package/components/identity.bans/tsconfig.json +1 -1
  5. package/components/identity.bans/tsconfig.tsbuildinfo +1 -1
  6. package/components/identity.bans/types/index.d.ts +1 -1
  7. package/components/identity.basic/operations/add.js +1 -1
  8. package/components/identity.basic/operations/authenticate.js +1 -1
  9. package/components/identity.basic/operations/check.js +1 -1
  10. package/components/identity.basic/operations/delete.js +1 -1
  11. package/components/identity.basic/operations/incept.js +18 -2
  12. package/components/identity.basic/operations/info.js +1 -1
  13. package/components/identity.basic/operations/lib/credentials.js +1 -1
  14. package/components/identity.basic/operations/transit.js +1 -1
  15. package/components/identity.basic/source/incept.ts +29 -1
  16. package/components/identity.basic/tsconfig.json +1 -1
  17. package/components/identity.basic/tsconfig.tsbuildinfo +1 -1
  18. package/components/identity.basic/types/index.d.ts +3 -2
  19. package/components/identity.clients/operations/describe.js +1 -1
  20. package/components/identity.clients/operations/lib/Context.js +1 -1
  21. package/components/identity.clients/operations/lib/Entity.js +1 -1
  22. package/components/identity.clients/operations/lib/canonical.js +1 -1
  23. package/components/identity.clients/operations/lib/cimd.js +1 -1
  24. package/components/identity.clients/operations/lib/errors.js +1 -1
  25. package/components/identity.clients/operations/lib/index.js +1 -1
  26. package/components/identity.clients/operations/lib/redirect.js +1 -1
  27. package/components/identity.clients/operations/register.js +1 -1
  28. package/components/identity.clients/tsconfig.json +1 -1
  29. package/components/identity.clients/tsconfig.tsbuildinfo +1 -1
  30. package/components/identity.clients/types/index.d.ts +1 -1
  31. package/components/identity.credentials/operations/list.js +1 -1
  32. package/components/identity.credentials/tsconfig.json +4 -2
  33. package/components/identity.credentials/tsconfig.tsbuildinfo +1 -1
  34. package/components/identity.credentials/types/index.d.ts +1 -1
  35. package/components/identity.federation/operations/authenticate.js +7 -3
  36. package/components/identity.federation/operations/create.js +1 -1
  37. package/components/identity.federation/operations/decode.js +1 -1
  38. package/components/identity.federation/operations/delete.js +1 -1
  39. package/components/identity.federation/operations/incept.js +6 -2
  40. package/components/identity.federation/operations/lib/Configuration.js +1 -1
  41. package/components/identity.federation/operations/lib/Ctx.js +1 -1
  42. package/components/identity.federation/operations/lib/Payload.js +1 -1
  43. package/components/identity.federation/operations/lib/decode.js +1 -1
  44. package/components/identity.federation/operations/lib/discovery.js +1 -1
  45. package/components/identity.federation/operations/lib/errors.js +1 -1
  46. package/components/identity.federation/operations/lib/exchange.js +1 -1
  47. package/components/identity.federation/operations/lib/index.js +2 -1
  48. package/components/identity.federation/operations/lib/jose.js +1 -1
  49. package/components/identity.federation/operations/lib/principal.js +14 -0
  50. package/components/identity.federation/operations/lib/resolve.js +1 -1
  51. package/components/identity.federation/operations/list.js +1 -1
  52. package/components/identity.federation/operations/types/Scheme.js +1 -1
  53. package/components/identity.federation/operations/types/configuration.js +1 -1
  54. package/components/identity.federation/operations/types/context.js +1 -1
  55. package/components/identity.federation/operations/types/entity.js +1 -1
  56. package/components/identity.federation/operations/types/index.js +1 -1
  57. package/components/identity.federation/source/authenticate.ts +8 -2
  58. package/components/identity.federation/source/incept.ts +7 -1
  59. package/components/identity.federation/source/lib/index.ts +1 -0
  60. package/components/identity.federation/source/lib/principal.ts +17 -0
  61. package/components/identity.federation/source/types/context.ts +3 -0
  62. package/components/identity.federation/tsconfig.json +4 -2
  63. package/components/identity.federation/tsconfig.tsbuildinfo +1 -1
  64. package/components/identity.federation/types/index.d.ts +1 -1
  65. package/components/identity.grants/operations/authorize.js +1 -1
  66. package/components/identity.grants/operations/exchange.js +1 -1
  67. package/components/identity.grants/operations/lib/code.js +1 -1
  68. package/components/identity.grants/operations/lib/identify.js +1 -1
  69. package/components/identity.grants/operations/lib/index.js +1 -1
  70. package/components/identity.grants/operations/list.js +1 -1
  71. package/components/identity.grants/operations/revoke.js +1 -1
  72. package/components/identity.grants/tsconfig.json +1 -1
  73. package/components/identity.grants/tsconfig.tsbuildinfo +1 -1
  74. package/components/identity.grants/types/index.d.ts +1 -1
  75. package/components/identity.keys/operations/create.js +1 -1
  76. package/components/identity.keys/operations/disable.js +1 -1
  77. package/components/identity.keys/operations/revoke.js +1 -1
  78. package/components/identity.keys/tsconfig.json +1 -1
  79. package/components/identity.keys/tsconfig.tsbuildinfo +1 -1
  80. package/components/identity.keys/types/index.d.ts +1 -1
  81. package/components/identity.otp/operations/authenticate.js +1 -1
  82. package/components/identity.otp/operations/issue.js +1 -1
  83. package/components/identity.otp/operations/lib/Context.js +1 -1
  84. package/components/identity.otp/operations/lib/Entity.js +1 -1
  85. package/components/identity.otp/operations/lib/index.js +1 -1
  86. package/components/identity.otp/tsconfig.json +1 -1
  87. package/components/identity.otp/tsconfig.tsbuildinfo +1 -1
  88. package/components/identity.otp/types/index.d.ts +1 -1
  89. package/components/identity.passkeys/operations/authenticate.js +1 -1
  90. package/components/identity.passkeys/operations/challenge.js +1 -1
  91. package/components/identity.passkeys/operations/create.js +1 -1
  92. package/components/identity.passkeys/operations/delete.js +1 -1
  93. package/components/identity.passkeys/operations/lib/const.js +1 -1
  94. package/components/identity.passkeys/operations/list.js +1 -1
  95. package/components/identity.passkeys/operations/types/Configuration.js +1 -1
  96. package/components/identity.passkeys/operations/types/Context.js +1 -1
  97. package/components/identity.passkeys/operations/types/Passkey.js +1 -1
  98. package/components/identity.passkeys/operations/types/index.js +1 -1
  99. package/components/identity.passkeys/operations/use.js +1 -1
  100. package/components/identity.passkeys/tsconfig.json +1 -1
  101. package/components/identity.passkeys/tsconfig.tsbuildinfo +1 -1
  102. package/components/identity.passkeys/types/index.d.ts +1 -1
  103. package/components/identity.roles/operations/grant.js +1 -1
  104. package/components/identity.roles/operations/lib/Entity.js +1 -1
  105. package/components/identity.roles/operations/list.js +1 -1
  106. package/components/identity.roles/operations/principal.js +29 -5
  107. package/components/identity.roles/source/principal.ts +33 -5
  108. package/components/identity.roles/tsconfig.json +1 -1
  109. package/components/identity.roles/tsconfig.tsbuildinfo +1 -1
  110. package/components/identity.roles/types/index.d.ts +1 -1
  111. package/components/identity.tokens/operations/authenticate.js +1 -1
  112. package/components/identity.tokens/operations/decrypt.js +1 -1
  113. package/components/identity.tokens/operations/encrypt.js +1 -1
  114. package/components/identity.tokens/operations/issue.js +1 -1
  115. package/components/identity.tokens/operations/lib/form.js +1 -1
  116. package/components/identity.tokens/operations/lib/index.js +1 -1
  117. package/components/identity.tokens/operations/lib/jose.js +1 -1
  118. package/components/identity.tokens/operations/lib/key.js +1 -1
  119. package/components/identity.tokens/operations/lib/pad.js +1 -1
  120. package/components/identity.tokens/operations/revoke.js +1 -1
  121. package/components/identity.tokens/tsconfig.json +1 -1
  122. package/components/identity.tokens/tsconfig.tsbuildinfo +1 -1
  123. package/components/identity.tokens/types/index.d.ts +1 -1
  124. package/documentation/access.md +13 -0
  125. package/documentation/components.md +3 -0
  126. package/documentation/introspection.md +13 -5
  127. package/documentation/io.md +6 -0
  128. package/documentation/map.md +8 -0
  129. package/documentation/mcp.md +186 -0
  130. package/documentation/oauth.md +8 -7
  131. package/documentation/rpc.md +144 -0
  132. package/documentation/tree.md +3 -0
  133. package/features/identity.basic.feature +44 -0
  134. package/features/identity.federation.feature +2 -5
  135. package/features/introspection.feature +333 -0
  136. package/features/mcp.feature +691 -0
  137. package/features/oauth.discovery.feature +10 -11
  138. package/features/oauth.grants.feature +22 -9
  139. package/features/octets.cloudinary.feature +1 -0
  140. package/features/rpc.feature +429 -0
  141. package/features/steps/Cloudinary.ts +13 -0
  142. package/features/steps/Components.ts +0 -4
  143. package/features/steps/Gateway.ts +19 -2
  144. package/features/steps/Parameters.ts +18 -7
  145. package/features/steps/Realtime.ts +3 -0
  146. package/features/steps/components/echo/manifest.toa.yaml +1 -0
  147. package/features/steps/components/pots/manifest.toa.yaml +2 -0
  148. package/package.json +3 -3
  149. package/readme.md +3 -0
  150. package/schemas/annotation.cos.yaml +33 -0
  151. package/schemas/call.cos.yaml +18 -0
  152. package/source/Annotation.ts +31 -0
  153. package/source/Directive.test.ts +15 -15
  154. package/source/Directive.ts +77 -9
  155. package/source/Endpoint.test.ts +67 -0
  156. package/source/Endpoint.ts +31 -11
  157. package/source/Factory.ts +5 -1
  158. package/source/Gateway.ts +73 -11
  159. package/source/HTTP/Context.ts +7 -0
  160. package/source/HTTP/Server.ts +7 -1
  161. package/source/HTTP/exceptions.ts +2 -2
  162. package/source/HTTP/messages.ts +10 -1
  163. package/source/Introspection.ts +105 -0
  164. package/source/MCP/Server.ts +275 -0
  165. package/source/MCP/discover.ts +52 -0
  166. package/source/MCP/errors.ts +81 -0
  167. package/source/MCP/index.ts +1 -0
  168. package/source/MCP/schema.test.ts +85 -0
  169. package/source/MCP/schema.ts +87 -0
  170. package/source/MCP/tools.ts +157 -0
  171. package/source/MCP/types.ts +84 -0
  172. package/source/Query.ts +48 -8
  173. package/source/RPC/Context.ts +78 -0
  174. package/source/RPC/Dispatcher.ts +130 -0
  175. package/source/RPC/errors.test.ts +52 -0
  176. package/source/RPC/errors.ts +83 -0
  177. package/source/RPC/index.ts +1 -0
  178. package/source/RPC/names.test.ts +122 -0
  179. package/source/RPC/names.ts +183 -0
  180. package/source/RPC/types.ts +34 -0
  181. package/source/RTD/Directives.ts +52 -2
  182. package/source/RTD/Endpoint.ts +2 -1
  183. package/source/RTD/Method.ts +14 -11
  184. package/source/RTD/Node.ts +38 -7
  185. package/source/RTD/Route.ts +30 -3
  186. package/source/RTD/Tree.ts +37 -1
  187. package/source/RTD/expiration.test.ts +1 -1
  188. package/source/RTD/walk.test.ts +110 -0
  189. package/source/const.ts +15 -0
  190. package/source/deployment.ts +8 -1
  191. package/source/directives/auth/Anonymous.test.ts +38 -0
  192. package/source/directives/auth/Anonymous.ts +12 -0
  193. package/source/directives/auth/Anyone.ts +4 -0
  194. package/source/directives/auth/Authorization.ts +62 -3
  195. package/source/directives/auth/Delegate.test.ts +36 -0
  196. package/source/directives/auth/Delegate.ts +14 -0
  197. package/source/directives/auth/Echo.ts +5 -0
  198. package/source/directives/auth/Incept.ts +2 -1
  199. package/source/directives/auth/Role.ts +13 -0
  200. package/source/directives/auth/Rule.ts +29 -0
  201. package/source/directives/auth/Scheme.ts +5 -0
  202. package/source/directives/auth/types.ts +21 -0
  203. package/source/directives/cache/Cache.ts +1 -1
  204. package/source/directives/dev/Development.ts +1 -1
  205. package/source/directives/flow/Flow.ts +1 -1
  206. package/source/directives/index.ts +3 -1
  207. package/source/directives/io/Directive.ts +1 -1
  208. package/source/directives/io/IO.ts +32 -3
  209. package/source/directives/io/Input.ts +3 -2
  210. package/source/directives/io/Output.ts +6 -3
  211. package/source/directives/io/Status.test.ts +2 -2
  212. package/source/directives/io/Status.ts +1 -1
  213. package/source/directives/io/Throttle.ts +1 -1
  214. package/source/directives/io/lib/throttle/Quotas.ts +2 -2
  215. package/source/directives/map/Headers.ts +11 -0
  216. package/source/directives/map/Map.ts +10 -1
  217. package/source/directives/map/Mapping.ts +23 -0
  218. package/source/directives/map/Segments.ts +12 -0
  219. package/source/directives/mcp/MCP.ts +40 -0
  220. package/source/directives/mcp/Tool.test.ts +90 -0
  221. package/source/directives/mcp/Tool.ts +47 -0
  222. package/source/directives/mcp/index.ts +6 -0
  223. package/source/directives/oauth/Discovery.ts +10 -16
  224. package/source/directives/octets/Octets.ts +1 -1
  225. package/source/directives/require/Directive.ts +1 -1
  226. package/source/directives/require/Headers.ts +1 -1
  227. package/source/directives/require/Require.ts +2 -2
  228. package/source/schemas.ts +2 -0
  229. package/transpiled/Annotation.d.ts +24 -0
  230. package/transpiled/Directive.d.ts +18 -1
  231. package/transpiled/Directive.js +50 -6
  232. package/transpiled/Directive.js.map +1 -1
  233. package/transpiled/Endpoint.d.ts +9 -0
  234. package/transpiled/Endpoint.js +27 -11
  235. package/transpiled/Endpoint.js.map +1 -1
  236. package/transpiled/Factory.js +5 -1
  237. package/transpiled/Factory.js.map +1 -1
  238. package/transpiled/Gateway.d.ts +19 -2
  239. package/transpiled/Gateway.js +51 -9
  240. package/transpiled/Gateway.js.map +1 -1
  241. package/transpiled/HTTP/Context.d.ts +6 -0
  242. package/transpiled/HTTP/Context.js +6 -0
  243. package/transpiled/HTTP/Context.js.map +1 -1
  244. package/transpiled/HTTP/Server.d.ts +5 -1
  245. package/transpiled/HTTP/exceptions.d.ts +1 -1
  246. package/transpiled/HTTP/exceptions.js +2 -2
  247. package/transpiled/HTTP/exceptions.js.map +1 -1
  248. package/transpiled/HTTP/messages.d.ts +6 -0
  249. package/transpiled/HTTP/messages.js +9 -1
  250. package/transpiled/HTTP/messages.js.map +1 -1
  251. package/transpiled/Introspection.d.ts +42 -0
  252. package/transpiled/Introspection.js +50 -1
  253. package/transpiled/Introspection.js.map +1 -1
  254. package/transpiled/MCP/Server.d.ts +41 -0
  255. package/transpiled/MCP/Server.js +180 -0
  256. package/transpiled/MCP/Server.js.map +1 -0
  257. package/transpiled/MCP/discover.d.ts +13 -0
  258. package/transpiled/MCP/discover.js +29 -0
  259. package/transpiled/MCP/discover.js.map +1 -0
  260. package/transpiled/MCP/errors.d.ts +24 -0
  261. package/transpiled/MCP/errors.js +67 -0
  262. package/transpiled/MCP/errors.js.map +1 -0
  263. package/transpiled/MCP/index.d.ts +1 -0
  264. package/transpiled/MCP/index.js +2 -0
  265. package/transpiled/MCP/index.js.map +1 -0
  266. package/transpiled/MCP/schema.d.ts +18 -0
  267. package/transpiled/MCP/schema.js +64 -0
  268. package/transpiled/MCP/schema.js.map +1 -0
  269. package/transpiled/MCP/tools.d.ts +31 -0
  270. package/transpiled/MCP/tools.js +122 -0
  271. package/transpiled/MCP/tools.js.map +1 -0
  272. package/transpiled/MCP/types.d.ts +66 -0
  273. package/transpiled/MCP/types.js +13 -0
  274. package/transpiled/MCP/types.js.map +1 -0
  275. package/transpiled/Query.d.ts +7 -0
  276. package/transpiled/Query.js +38 -7
  277. package/transpiled/Query.js.map +1 -1
  278. package/transpiled/RPC/Context.d.ts +11 -0
  279. package/transpiled/RPC/Context.js +63 -0
  280. package/transpiled/RPC/Context.js.map +1 -0
  281. package/transpiled/RPC/Dispatcher.d.ts +19 -0
  282. package/transpiled/RPC/Dispatcher.js +100 -0
  283. package/transpiled/RPC/Dispatcher.js.map +1 -0
  284. package/transpiled/RPC/errors.d.ts +18 -0
  285. package/transpiled/RPC/errors.js +67 -0
  286. package/transpiled/RPC/errors.js.map +1 -0
  287. package/transpiled/RPC/index.d.ts +1 -0
  288. package/transpiled/RPC/index.js +2 -0
  289. package/transpiled/RPC/index.js.map +1 -0
  290. package/transpiled/RPC/names.d.ts +31 -0
  291. package/transpiled/RPC/names.js +121 -0
  292. package/transpiled/RPC/names.js.map +1 -0
  293. package/transpiled/RPC/types.d.ts +27 -0
  294. package/transpiled/RPC/types.js +8 -0
  295. package/transpiled/RPC/types.js.map +1 -0
  296. package/transpiled/RTD/Directives.d.ts +41 -2
  297. package/transpiled/RTD/Endpoint.d.ts +2 -1
  298. package/transpiled/RTD/Method.d.ts +8 -3
  299. package/transpiled/RTD/Method.js +12 -10
  300. package/transpiled/RTD/Method.js.map +1 -1
  301. package/transpiled/RTD/Node.d.ts +20 -2
  302. package/transpiled/RTD/Node.js +22 -4
  303. package/transpiled/RTD/Node.js.map +1 -1
  304. package/transpiled/RTD/Route.d.ts +2 -1
  305. package/transpiled/RTD/Route.js +27 -2
  306. package/transpiled/RTD/Route.js.map +1 -1
  307. package/transpiled/RTD/Tree.d.ts +3 -1
  308. package/transpiled/RTD/Tree.js +26 -0
  309. package/transpiled/RTD/Tree.js.map +1 -1
  310. package/transpiled/const.d.ts +12 -0
  311. package/transpiled/const.js +12 -0
  312. package/transpiled/const.js.map +1 -1
  313. package/transpiled/deployment.js +4 -0
  314. package/transpiled/deployment.js.map +1 -1
  315. package/transpiled/directives/auth/Anonymous.d.ts +6 -0
  316. package/transpiled/directives/auth/Anonymous.js +10 -0
  317. package/transpiled/directives/auth/Anonymous.js.map +1 -1
  318. package/transpiled/directives/auth/Anyone.d.ts +1 -0
  319. package/transpiled/directives/auth/Anyone.js +3 -0
  320. package/transpiled/directives/auth/Anyone.js.map +1 -1
  321. package/transpiled/directives/auth/Authorization.d.ts +27 -1
  322. package/transpiled/directives/auth/Authorization.js +49 -1
  323. package/transpiled/directives/auth/Authorization.js.map +1 -1
  324. package/transpiled/directives/auth/Delegate.d.ts +5 -0
  325. package/transpiled/directives/auth/Delegate.js +10 -0
  326. package/transpiled/directives/auth/Delegate.js.map +1 -1
  327. package/transpiled/directives/auth/Echo.d.ts +2 -0
  328. package/transpiled/directives/auth/Echo.js +4 -0
  329. package/transpiled/directives/auth/Echo.js.map +1 -1
  330. package/transpiled/directives/auth/Incept.js +2 -1
  331. package/transpiled/directives/auth/Incept.js.map +1 -1
  332. package/transpiled/directives/auth/Role.d.ts +2 -0
  333. package/transpiled/directives/auth/Role.js +9 -0
  334. package/transpiled/directives/auth/Role.js.map +1 -1
  335. package/transpiled/directives/auth/Rule.d.ts +5 -0
  336. package/transpiled/directives/auth/Rule.js +20 -0
  337. package/transpiled/directives/auth/Rule.js.map +1 -1
  338. package/transpiled/directives/auth/Scheme.d.ts +2 -0
  339. package/transpiled/directives/auth/Scheme.js +4 -0
  340. package/transpiled/directives/auth/Scheme.js.map +1 -1
  341. package/transpiled/directives/auth/types.d.ts +16 -0
  342. package/transpiled/directives/cache/Cache.d.ts +1 -1
  343. package/transpiled/directives/cache/Cache.js +1 -1
  344. package/transpiled/directives/cache/Cache.js.map +1 -1
  345. package/transpiled/directives/dev/Development.d.ts +1 -1
  346. package/transpiled/directives/dev/Development.js +1 -1
  347. package/transpiled/directives/dev/Development.js.map +1 -1
  348. package/transpiled/directives/flow/Flow.d.ts +1 -1
  349. package/transpiled/directives/flow/Flow.js +1 -1
  350. package/transpiled/directives/flow/Flow.js.map +1 -1
  351. package/transpiled/directives/index.js +2 -1
  352. package/transpiled/directives/index.js.map +1 -1
  353. package/transpiled/directives/io/Directive.d.ts +1 -1
  354. package/transpiled/directives/io/IO.d.ts +7 -1
  355. package/transpiled/directives/io/IO.js +23 -3
  356. package/transpiled/directives/io/IO.js.map +1 -1
  357. package/transpiled/directives/io/Input.d.ts +3 -2
  358. package/transpiled/directives/io/Input.js +2 -1
  359. package/transpiled/directives/io/Input.js.map +1 -1
  360. package/transpiled/directives/io/Output.d.ts +5 -3
  361. package/transpiled/directives/io/Output.js +4 -2
  362. package/transpiled/directives/io/Output.js.map +1 -1
  363. package/transpiled/directives/io/Status.d.ts +1 -1
  364. package/transpiled/directives/io/Status.js +1 -1
  365. package/transpiled/directives/io/Status.js.map +1 -1
  366. package/transpiled/directives/io/Throttle.d.ts +1 -1
  367. package/transpiled/directives/io/Throttle.js +1 -1
  368. package/transpiled/directives/io/Throttle.js.map +1 -1
  369. package/transpiled/directives/io/lib/throttle/Quotas.d.ts +1 -1
  370. package/transpiled/directives/io/lib/throttle/Quotas.js +2 -2
  371. package/transpiled/directives/io/lib/throttle/Quotas.js.map +1 -1
  372. package/transpiled/directives/map/Headers.d.ts +2 -0
  373. package/transpiled/directives/map/Headers.js +8 -0
  374. package/transpiled/directives/map/Headers.js.map +1 -1
  375. package/transpiled/directives/map/Map.d.ts +3 -1
  376. package/transpiled/directives/map/Map.js +7 -1
  377. package/transpiled/directives/map/Map.js.map +1 -1
  378. package/transpiled/directives/map/Mapping.d.ts +13 -0
  379. package/transpiled/directives/map/Mapping.js +20 -0
  380. package/transpiled/directives/map/Mapping.js.map +1 -1
  381. package/transpiled/directives/map/Segments.d.ts +3 -0
  382. package/transpiled/directives/map/Segments.js +9 -0
  383. package/transpiled/directives/map/Segments.js.map +1 -1
  384. package/transpiled/directives/mcp/MCP.d.ts +15 -0
  385. package/transpiled/directives/mcp/MCP.js +29 -0
  386. package/transpiled/directives/mcp/MCP.js.map +1 -0
  387. package/transpiled/directives/mcp/Tool.d.ts +18 -0
  388. package/transpiled/directives/mcp/Tool.js +34 -0
  389. package/transpiled/directives/mcp/Tool.js.map +1 -0
  390. package/transpiled/directives/mcp/index.d.ts +4 -0
  391. package/transpiled/directives/mcp/index.js +4 -0
  392. package/transpiled/directives/mcp/index.js.map +1 -0
  393. package/transpiled/directives/oauth/Discovery.js +10 -13
  394. package/transpiled/directives/oauth/Discovery.js.map +1 -1
  395. package/transpiled/directives/octets/Octets.d.ts +1 -1
  396. package/transpiled/directives/octets/Octets.js +1 -1
  397. package/transpiled/directives/octets/Octets.js.map +1 -1
  398. package/transpiled/directives/require/Directive.d.ts +1 -1
  399. package/transpiled/directives/require/Headers.d.ts +1 -1
  400. package/transpiled/directives/require/Headers.js +1 -1
  401. package/transpiled/directives/require/Headers.js.map +1 -1
  402. package/transpiled/directives/require/Require.d.ts +1 -1
  403. package/transpiled/directives/require/Require.js +2 -2
  404. package/transpiled/directives/require/Require.js.map +1 -1
  405. package/transpiled/schemas.d.ts +2 -0
  406. package/transpiled/schemas.js +1 -0
  407. package/transpiled/schemas.js.map +1 -1
  408. package/tsconfig.tsbuildinfo +1 -1
  409. package/components/identity.bans/operations/transit.d.ts +0 -14
  410. package/components/identity.bans/operations/transit.js.map +0 -1
  411. package/components/identity.basic/operations/add.d.ts +0 -3
  412. package/components/identity.basic/operations/add.js.map +0 -1
  413. package/components/identity.basic/operations/authenticate.d.ts +0 -13
  414. package/components/identity.basic/operations/authenticate.js.map +0 -1
  415. package/components/identity.basic/operations/check.d.ts +0 -7
  416. package/components/identity.basic/operations/check.js.map +0 -1
  417. package/components/identity.basic/operations/delete.d.ts +0 -7
  418. package/components/identity.basic/operations/delete.js.map +0 -1
  419. package/components/identity.basic/operations/incept.d.ts +0 -12
  420. package/components/identity.basic/operations/incept.js.map +0 -1
  421. package/components/identity.basic/operations/info.d.ts +0 -10
  422. package/components/identity.basic/operations/info.js.map +0 -1
  423. package/components/identity.basic/operations/lib/credentials.d.ts +0 -5
  424. package/components/identity.basic/operations/lib/credentials.js.map +0 -1
  425. package/components/identity.basic/operations/transit.d.ts +0 -15
  426. package/components/identity.basic/operations/transit.js.map +0 -1
  427. package/components/identity.clients/operations/describe.d.ts +0 -27
  428. package/components/identity.clients/operations/describe.js.map +0 -1
  429. package/components/identity.clients/operations/lib/Context.d.ts +0 -29
  430. package/components/identity.clients/operations/lib/Context.js.map +0 -1
  431. package/components/identity.clients/operations/lib/Entity.d.ts +0 -29
  432. package/components/identity.clients/operations/lib/Entity.js.map +0 -1
  433. package/components/identity.clients/operations/lib/canonical.d.ts +0 -11
  434. package/components/identity.clients/operations/lib/canonical.js.map +0 -1
  435. package/components/identity.clients/operations/lib/cimd.d.ts +0 -8
  436. package/components/identity.clients/operations/lib/cimd.js.map +0 -1
  437. package/components/identity.clients/operations/lib/errors.d.ts +0 -7
  438. package/components/identity.clients/operations/lib/errors.js.map +0 -1
  439. package/components/identity.clients/operations/lib/index.d.ts +0 -6
  440. package/components/identity.clients/operations/lib/index.js.map +0 -1
  441. package/components/identity.clients/operations/lib/redirect.d.ts +0 -10
  442. package/components/identity.clients/operations/lib/redirect.js.map +0 -1
  443. package/components/identity.clients/operations/register.d.ts +0 -37
  444. package/components/identity.clients/operations/register.js.map +0 -1
  445. package/components/identity.credentials/operations/list.d.ts +0 -52
  446. package/components/identity.credentials/operations/list.js.map +0 -1
  447. package/components/identity.federation/operations/authenticate.d.ts +0 -16
  448. package/components/identity.federation/operations/authenticate.js.map +0 -1
  449. package/components/identity.federation/operations/create.d.ts +0 -8
  450. package/components/identity.federation/operations/create.js.map +0 -1
  451. package/components/identity.federation/operations/decode.d.ts +0 -3
  452. package/components/identity.federation/operations/decode.js.map +0 -1
  453. package/components/identity.federation/operations/delete.d.ts +0 -8
  454. package/components/identity.federation/operations/delete.js.map +0 -1
  455. package/components/identity.federation/operations/incept.d.ts +0 -11
  456. package/components/identity.federation/operations/incept.js.map +0 -1
  457. package/components/identity.federation/operations/lib/Configuration.d.ts +0 -39
  458. package/components/identity.federation/operations/lib/Configuration.js.map +0 -1
  459. package/components/identity.federation/operations/lib/Ctx.d.ts +0 -8
  460. package/components/identity.federation/operations/lib/Ctx.js.map +0 -1
  461. package/components/identity.federation/operations/lib/Payload.d.ts +0 -5
  462. package/components/identity.federation/operations/lib/Payload.js.map +0 -1
  463. package/components/identity.federation/operations/lib/decode.d.ts +0 -3
  464. package/components/identity.federation/operations/lib/decode.js.map +0 -1
  465. package/components/identity.federation/operations/lib/discovery.d.ts +0 -5
  466. package/components/identity.federation/operations/lib/discovery.js.map +0 -1
  467. package/components/identity.federation/operations/lib/errors.d.ts +0 -77
  468. package/components/identity.federation/operations/lib/errors.js.map +0 -1
  469. package/components/identity.federation/operations/lib/exchange.d.ts +0 -3
  470. package/components/identity.federation/operations/lib/exchange.js.map +0 -1
  471. package/components/identity.federation/operations/lib/index.d.ts +0 -4
  472. package/components/identity.federation/operations/lib/index.js.map +0 -1
  473. package/components/identity.federation/operations/lib/jose.d.ts +0 -1
  474. package/components/identity.federation/operations/lib/jose.js.map +0 -1
  475. package/components/identity.federation/operations/lib/resolve.d.ts +0 -3
  476. package/components/identity.federation/operations/lib/resolve.js.map +0 -1
  477. package/components/identity.federation/operations/list.d.ts +0 -7
  478. package/components/identity.federation/operations/list.js.map +0 -1
  479. package/components/identity.federation/operations/types/Scheme.d.ts +0 -1
  480. package/components/identity.federation/operations/types/Scheme.js.map +0 -1
  481. package/components/identity.federation/operations/types/configuration.d.ts +0 -22
  482. package/components/identity.federation/operations/types/configuration.js.map +0 -1
  483. package/components/identity.federation/operations/types/context.d.ts +0 -36
  484. package/components/identity.federation/operations/types/context.js.map +0 -1
  485. package/components/identity.federation/operations/types/entity.d.ts +0 -9
  486. package/components/identity.federation/operations/types/entity.js.map +0 -1
  487. package/components/identity.federation/operations/types/index.d.ts +0 -4
  488. package/components/identity.federation/operations/types/index.js.map +0 -1
  489. package/components/identity.grants/operations/authorize.d.ts +0 -35
  490. package/components/identity.grants/operations/authorize.js.map +0 -1
  491. package/components/identity.grants/operations/exchange.d.ts +0 -37
  492. package/components/identity.grants/operations/exchange.js.map +0 -1
  493. package/components/identity.grants/operations/lib/code.d.ts +0 -15
  494. package/components/identity.grants/operations/lib/code.js.map +0 -1
  495. package/components/identity.grants/operations/lib/identify.d.ts +0 -6
  496. package/components/identity.grants/operations/lib/identify.js.map +0 -1
  497. package/components/identity.grants/operations/lib/index.d.ts +0 -3
  498. package/components/identity.grants/operations/lib/index.js.map +0 -1
  499. package/components/identity.grants/operations/list.d.ts +0 -13
  500. package/components/identity.grants/operations/list.js.map +0 -1
  501. package/components/identity.grants/operations/revoke.d.ts +0 -18
  502. package/components/identity.grants/operations/revoke.js.map +0 -1
  503. package/components/identity.keys/operations/create.d.ts +0 -22
  504. package/components/identity.keys/operations/create.js.map +0 -1
  505. package/components/identity.keys/operations/disable.d.ts +0 -5
  506. package/components/identity.keys/operations/disable.js.map +0 -1
  507. package/components/identity.keys/operations/revoke.d.ts +0 -15
  508. package/components/identity.keys/operations/revoke.js.map +0 -1
  509. package/components/identity.otp/operations/authenticate.d.ts +0 -12
  510. package/components/identity.otp/operations/authenticate.js.map +0 -1
  511. package/components/identity.otp/operations/issue.d.ts +0 -12
  512. package/components/identity.otp/operations/issue.js.map +0 -1
  513. package/components/identity.otp/operations/lib/Context.d.ts +0 -16
  514. package/components/identity.otp/operations/lib/Context.js.map +0 -1
  515. package/components/identity.otp/operations/lib/Entity.d.ts +0 -6
  516. package/components/identity.otp/operations/lib/Entity.js.map +0 -1
  517. package/components/identity.otp/operations/lib/index.d.ts +0 -1
  518. package/components/identity.otp/operations/lib/index.js.map +0 -1
  519. package/components/identity.passkeys/operations/authenticate.d.ts +0 -16
  520. package/components/identity.passkeys/operations/authenticate.js.map +0 -1
  521. package/components/identity.passkeys/operations/challenge.d.ts +0 -35
  522. package/components/identity.passkeys/operations/challenge.js.map +0 -1
  523. package/components/identity.passkeys/operations/create.d.ts +0 -19
  524. package/components/identity.passkeys/operations/create.js.map +0 -1
  525. package/components/identity.passkeys/operations/delete.d.ts +0 -8
  526. package/components/identity.passkeys/operations/delete.js.map +0 -1
  527. package/components/identity.passkeys/operations/lib/const.d.ts +0 -1
  528. package/components/identity.passkeys/operations/lib/const.js.map +0 -1
  529. package/components/identity.passkeys/operations/list.d.ts +0 -7
  530. package/components/identity.passkeys/operations/list.js.map +0 -1
  531. package/components/identity.passkeys/operations/types/Configuration.d.ts +0 -6
  532. package/components/identity.passkeys/operations/types/Configuration.js.map +0 -1
  533. package/components/identity.passkeys/operations/types/Context.d.ts +0 -16
  534. package/components/identity.passkeys/operations/types/Context.js.map +0 -1
  535. package/components/identity.passkeys/operations/types/Passkey.d.ts +0 -12
  536. package/components/identity.passkeys/operations/types/Passkey.js.map +0 -1
  537. package/components/identity.passkeys/operations/types/index.d.ts +0 -2
  538. package/components/identity.passkeys/operations/types/index.js.map +0 -1
  539. package/components/identity.passkeys/operations/use.d.ts +0 -16
  540. package/components/identity.passkeys/operations/use.js.map +0 -1
  541. package/components/identity.roles/operations/grant.d.ts +0 -10
  542. package/components/identity.roles/operations/grant.js.map +0 -1
  543. package/components/identity.roles/operations/lib/Entity.d.ts +0 -5
  544. package/components/identity.roles/operations/lib/Entity.js.map +0 -1
  545. package/components/identity.roles/operations/list.d.ts +0 -2
  546. package/components/identity.roles/operations/list.js.map +0 -1
  547. package/components/identity.roles/operations/principal.d.ts +0 -13
  548. package/components/identity.roles/operations/principal.js.map +0 -1
  549. package/components/identity.tokens/operations/authenticate.d.ts +0 -10
  550. package/components/identity.tokens/operations/authenticate.js.map +0 -1
  551. package/components/identity.tokens/operations/decrypt.d.ts +0 -16
  552. package/components/identity.tokens/operations/decrypt.js.map +0 -1
  553. package/components/identity.tokens/operations/encrypt.d.ts +0 -9
  554. package/components/identity.tokens/operations/encrypt.js.map +0 -1
  555. package/components/identity.tokens/operations/issue.d.ts +0 -25
  556. package/components/identity.tokens/operations/issue.js.map +0 -1
  557. package/components/identity.tokens/operations/lib/form.d.ts +0 -8
  558. package/components/identity.tokens/operations/lib/form.js.map +0 -1
  559. package/components/identity.tokens/operations/lib/index.d.ts +0 -4
  560. package/components/identity.tokens/operations/lib/index.js.map +0 -1
  561. package/components/identity.tokens/operations/lib/jose.d.ts +0 -1
  562. package/components/identity.tokens/operations/lib/jose.js.map +0 -1
  563. package/components/identity.tokens/operations/lib/key.d.ts +0 -1
  564. package/components/identity.tokens/operations/lib/key.js.map +0 -1
  565. package/components/identity.tokens/operations/lib/pad.d.ts +0 -1
  566. package/components/identity.tokens/operations/lib/pad.js.map +0 -1
  567. package/components/identity.tokens/operations/revoke.d.ts +0 -2
  568. package/components/identity.tokens/operations/revoke.js.map +0 -1
package/source/Gateway.ts CHANGED
@@ -3,10 +3,13 @@ import { setTimeout } from 'node:timers/promises'
3
3
  import { console } from 'openspan'
4
4
  import { type bindings, Connector } from '@toa.io/core'
5
5
  import * as http from './HTTP/index.js'
6
+ import { MCP, RPC } from './const.js'
6
7
  import { rethrow } from './exceptions.js'
7
8
  import { decide } from './Branch.js'
8
9
  import type { Interception } from './Interception.js'
9
- import type { Method, Node, Parameter, Tree, Match } from './RTD/index.js'
10
+ import type { Dispatcher } from './RPC/index.js'
11
+ import type { Server } from './MCP/index.js'
12
+ import type { DirectiveFactory, Method, Node, Parameter, Tree, Match } from './RTD/index.js'
10
13
  import type { Label } from './discovery.js'
11
14
  import type { Branch, Exposed } from './Branch.js'
12
15
 
@@ -14,6 +17,13 @@ export class Gateway extends Connector {
14
17
  private readonly broadcast: Broadcast
15
18
  private readonly tree: Tree
16
19
  private readonly interceptor: Interception
20
+ private readonly directives: DirectiveFactory
21
+
22
+ /** JSON-RPC is served only where the annotation asked for it. */
23
+ private readonly dispatcher: Dispatcher | null
24
+
25
+ /** And the same of MCP. */
26
+ private readonly mcp: Server | null
17
27
  private readonly branches = new Map<string, Exposed>()
18
28
  private lastMerge = 0
19
29
  private widestGap = 0
@@ -21,12 +31,17 @@ export class Gateway extends Connector {
21
31
  private stopped = false
22
32
  private resolveFirstMerge: (() => void) | null = null
23
33
 
24
- public constructor (broadcast: Broadcast, tree: Tree, interception: Interception) {
34
+ // eslint-disable-next-line max-params
35
+ public constructor (broadcast: Broadcast, tree: Tree, interception: Interception,
36
+ directives: DirectiveFactory, dispatcher: Dispatcher | null, mcp: Server | null) {
25
37
  super()
26
38
 
27
39
  this.broadcast = broadcast
28
40
  this.tree = tree
29
41
  this.interceptor = interception
42
+ this.directives = directives
43
+ this.dispatcher = dispatcher
44
+ this.mcp = mcp
30
45
 
31
46
  this.depends(broadcast)
32
47
  }
@@ -38,10 +53,44 @@ export class Gateway extends Connector {
38
53
  if (interception !== null)
39
54
  return interception
40
55
 
56
+ // request-scoped, before anything is routed: this is where a credential is read
57
+ await context.timing.capture('preflight',
58
+ this.directives.preflight(context)).catch(rethrow)
59
+
60
+ const response = await this.endpoint(context)
61
+
62
+ // request-scoped, on whatever is going back: this is where a credential is re-issued
63
+ await context.timing.capture('depart',
64
+ this.directives.depart(context, response)).catch(rethrow)
65
+
66
+ return response
67
+ }
68
+
69
+ /**
70
+ * What answers the request: a pinned endpoint that makes calls of its own, or the route
71
+ * the path names.
72
+ */
73
+ private async endpoint (context: http.Context): Promise<http.OutgoingMessage> {
74
+ const route: http.Processor = async (call) => await this.route(call)
75
+
76
+ if (this.dispatcher !== null && context.url.pathname === RPC)
77
+ return await context.timing.capture('rpc', this.dispatcher.dispatch(context, route))
78
+
79
+ if (this.mcp !== null && context.url.pathname === MCP)
80
+ return await context.timing.capture('mcp', this.mcp.process(context, route))
81
+
82
+ return await this.route(context)
83
+ }
84
+
85
+ /**
86
+ * One call: everything that needs a node. A request makes one of these, and a request
87
+ * that carries several calls makes one per call.
88
+ */
89
+ private async route (context: http.Context): Promise<http.OutgoingMessage> {
41
90
  const { node, parameters } = this.match(context)
42
91
 
43
92
  if (context.request.method === 'OPTIONS')
44
- return await this.explain(node, parameters)
93
+ return await this.explain(context, node, parameters)
45
94
 
46
95
  let verb = context.request.method
47
96
 
@@ -53,8 +102,8 @@ export class Gateway extends Connector {
53
102
 
54
103
  const method = node.methods[verb]
55
104
 
56
- const interruption = await context.timing.capture('preflight',
57
- method.directives.preflight(context, parameters)).catch(rethrow)
105
+ const interruption = await context.timing.capture('precall',
106
+ method.directives.precall(context, parameters)).catch(rethrow)
58
107
 
59
108
  const response = interruption ??
60
109
  await context.timing.capture('call', this.call(method, context, parameters))
@@ -68,7 +117,16 @@ export class Gateway extends Connector {
68
117
  protected override async open (): Promise<void> {
69
118
  await this.discover()
70
119
 
71
- console.info('Gateway started')
120
+ // what is served besides the tree, so that turning one on can be seen to have worked
121
+ const pinned: string[] = []
122
+
123
+ if (this.dispatcher !== null)
124
+ pinned.push(RPC)
125
+
126
+ if (this.mcp !== null)
127
+ pinned.push(MCP)
128
+
129
+ console.info('Gateway started', { endpoints: pinned.length === 0 ? 'none' : pinned.join(' ') })
72
130
  }
73
131
 
74
132
  /**
@@ -131,12 +189,16 @@ export class Gateway extends Connector {
131
189
  .catch(rethrow) as http.OutgoingMessage
132
190
  }
133
191
 
134
- private async explain (node: Node, parameters: Parameter[]): Promise<http.OutgoingMessage> {
135
- const body = await node.explain(parameters)
136
- const allow = [...Object.keys(node.methods)].join(', ')
137
- const headers = new Headers({ allow })
192
+ private async explain (context: http.Context, node: Node,
193
+ parameters: Parameter[]): Promise<http.OutgoingMessage> {
194
+ const body = await node.explain(context, parameters)
195
+ const verbs = Object.keys(body)
196
+
197
+ // what a caller may not use is not a resource to them, and describing it would be the leak
198
+ if (verbs.length === 0 && Object.keys(node.methods).length > 0)
199
+ throw new http.Forbidden()
138
200
 
139
- return { body, headers }
201
+ return { body, headers: new Headers({ allow: verbs.join(', ') }) }
140
202
  }
141
203
 
142
204
  private async discover (): Promise<void> {
@@ -22,6 +22,13 @@ export class Context {
22
22
  public readonly timing: Timing
23
23
  public readonly debug: boolean
24
24
 
25
+ /**
26
+ * Whether this is a procedure a request made, rather than the request. What forks one
27
+ * says so, and a directive that answers differently to a procedure than to a request
28
+ * reads it here.
29
+ */
30
+ public readonly procedural: boolean = false
31
+
25
32
  public readonly pipelines: Pipelines = {
26
33
  body: [],
27
34
  response: []
@@ -12,7 +12,7 @@ import { ClientError, Exception } from './exceptions.js'
12
12
  import { Context } from './Context.js'
13
13
  import { PROBE, Probe } from './Probe.js'
14
14
  import type { IncomingMessage, Protocol, ServerResponse } from './types.js'
15
- import type { Bouncer, OAuth } from '../Annotation.js'
15
+ import type { Bouncer, MCP, OAuth, RPC } from '../Annotation.js'
16
16
 
17
17
  export class Server extends Connector {
18
18
  private readonly server: http.Server | http2.Http2Server
@@ -389,6 +389,12 @@ interface Properties {
389
389
 
390
390
  /** The authorization server this context exposes; none is exposed without it. */
391
391
  oauth?: OAuth
392
+
393
+ /** JSON-RPC at `/.rpc`; none is served without it. */
394
+ rpc?: RPC
395
+
396
+ /** MCP at `/.mcp`; none is served without it. */
397
+ mcp?: MCP
392
398
  }
393
399
 
394
400
  export type Options = { authorities: Properties['authorities'] } & {
@@ -41,8 +41,8 @@ export class NotFound extends ClientError {
41
41
  }
42
42
 
43
43
  export class MethodNotAllowed extends ClientError {
44
- public constructor () {
45
- super(405)
44
+ public constructor (headers?: Headers) {
45
+ super(405, undefined, headers)
46
46
  }
47
47
  }
48
48
 
@@ -15,9 +15,18 @@ const server = `Exposition/${JSON.parse(readFileSync(new URL('../../package.json
15
15
 
16
16
  const pending = new Map<string, PendingStream>()
17
17
 
18
- export async function write (context: Context, response: ServerResponse, message: OutgoingMessage): Promise<void> {
18
+ /**
19
+ * Applies what the request accumulated in `pipelines.response` — an `io:output` restriction,
20
+ * a `vary` a `map` directive owes. Separate from `write` because a message is not always
21
+ * written: one call of several produces a value the reply is assembled from.
22
+ */
23
+ export async function shape (context: Context, message: OutgoingMessage): Promise<void> {
19
24
  for (const transform of context.pipelines.response)
20
25
  await transform(message)
26
+ }
27
+
28
+ export async function write (context: Context, response: ServerResponse, message: OutgoingMessage): Promise<void> {
29
+ await shape(context, message)
21
30
 
22
31
  if (message?.status !== undefined)
23
32
  response.statusCode = message.status
@@ -1,11 +1,116 @@
1
1
  import type { Remote } from '@toa.io/core'
2
2
 
3
3
  export interface Introspection {
4
+ /**
5
+ * What the route states this method is. The operation states what it is too, and that is
6
+ * not this: an operation is written without knowledge of any route, and a method is an
7
+ * operation and a route together — the same operation mounted twice is two methods, and
8
+ * one sentence cannot be true of both. The operation's own is for the Introspection.
9
+ */
10
+ description?: string
11
+
12
+ /** what a person is shown where a client lists this method, which a name is not */
13
+ title?: string
4
14
  route?: Record<string, Schema>
5
15
  query?: Record<string, Schema>
16
+
17
+ /** what a request header carries, which is therefore not the body's to send */
18
+ headers?: Record<string, Sourced>
6
19
  input?: Schema
7
20
  output?: Schema
8
21
  errors?: string[]
9
22
  }
10
23
 
24
+ /** A property the gateway reads from somewhere else, and the schema it was declared with. */
25
+ export interface Sourced {
26
+ header: string
27
+ [keyword: string]: unknown
28
+ }
29
+
11
30
  export type Schema = Awaited<ReturnType<Remote['explain']>>['input']
31
+
32
+ /**
33
+ * The same, in the order the shape states — whatever order the families that filled it ran
34
+ * in. What a resource says about itself is read, so it is written the way it is documented.
35
+ */
36
+ export function order (introspection: Introspection): Introspection {
37
+ const ordered: Introspection = {}
38
+
39
+ for (const key of KEYS)
40
+ if (introspection[key] !== undefined)
41
+ (ordered[key] as unknown) = introspection[key]
42
+
43
+ return ordered
44
+ }
45
+
46
+ const KEYS = ['title', 'description', 'route', 'query', 'headers', 'input', 'output', 'errors'] as const
47
+
48
+ /**
49
+ * The schema of one input property, taken out of it: a property another family fills is
50
+ * not the caller's to send, and what took it says where it comes from instead.
51
+ */
52
+ export function take (carrier: Carrier, property: string): Schema | undefined {
53
+ const input = carrier.input as Shape | null | undefined
54
+ const properties = input?.properties
55
+
56
+ if (input === undefined || input === null || properties === undefined ||
57
+ !(property in properties))
58
+ return undefined
59
+
60
+ const schema = properties[property]
61
+
62
+ delete properties[property]
63
+
64
+ if (input.required !== undefined)
65
+ input.required = input.required.filter((name) => name !== property)
66
+
67
+ return schema
68
+ }
69
+
70
+ /**
71
+ * A schema restricted to the properties a whitelist admits, and an array's items where it
72
+ * describes an array. What is not an object of properties is left alone: a whitelist has
73
+ * nothing to say about a string.
74
+ */
75
+ export function restrict (schema: Schema | undefined, allowed: Set<string>): Schema | undefined {
76
+ const shape = schema as Shape | null | undefined
77
+
78
+ if (shape === undefined || shape === null)
79
+ return schema
80
+
81
+ if (shape.items !== undefined)
82
+ return { ...shape, items: restrict(shape.items, allowed) } as unknown as Schema
83
+
84
+ if (shape.properties === undefined)
85
+ return schema
86
+
87
+ const properties: Record<string, Schema> = {}
88
+
89
+ for (const [name, property] of Object.entries(shape.properties))
90
+ if (allowed.has(name))
91
+ properties[name] = property
92
+
93
+ const restricted: Shape = { ...shape, properties }
94
+
95
+ if (shape.required !== undefined)
96
+ restricted.required = shape.required.filter((name) => allowed.has(name))
97
+
98
+ return restricted as unknown as Schema
99
+ }
100
+
101
+ /**
102
+ * What a schema is read as here: the keywords these narrow, and whatever else it carries.
103
+ * `Schema` as core declares it requires `properties`, which a schema of a string has not,
104
+ * so the two are cast through rather than assigned.
105
+ */
106
+ /** Whatever states an input: an explanation as the operation gave it, or as a route left it. */
107
+ interface Carrier {
108
+ input?: Schema
109
+ }
110
+
111
+ interface Shape {
112
+ properties?: Record<string, Schema>
113
+ required?: string[]
114
+ items?: Schema
115
+ [keyword: string]: unknown
116
+ }
@@ -0,0 +1,275 @@
1
+ import { console } from 'openspan'
2
+ import { BRANCH_TTL } from '../const.js'
3
+ import * as http from '../HTTP/index.js'
4
+ import { discovery, type Discovery } from './discover.js'
5
+ import { call, list, type Scope } from './tools.js'
6
+ import {
7
+ HEADER_MISMATCH,
8
+ INVALID_PARAMS,
9
+ INVALID_REQUEST,
10
+ METHOD_NOT_FOUND,
11
+ PARSE,
12
+ UNSUPPORTED_VERSION,
13
+ failure,
14
+ response
15
+ } from './errors.js'
16
+ import {
17
+ CLIENT_CAPABILITIES,
18
+ JSONRPC,
19
+ LEGACY,
20
+ MODERN,
21
+ PROTOCOL_VERSION,
22
+ SERVER_INFO,
23
+ VERSIONS,
24
+ type Cache,
25
+ type Message,
26
+ type Params
27
+ } from './types.js'
28
+ import type { Tree } from '../RTD/index.js'
29
+ import type { MCP } from '../Annotation.js'
30
+
31
+ /**
32
+ * The Model Context Protocol, as one endpoint that remembers nothing between requests.
33
+ *
34
+ * Two revisions are answered from it. The modern one carries the version and the client's
35
+ * capabilities in every request; the one before it opens with `initialize`, which is what
36
+ * most clients still send. Neither needs a session, and neither needs a stream: every method
37
+ * here answers one object, which is why this can exist in a package that serves no SSE.
38
+ */
39
+ export class Server {
40
+ private readonly options: MCP
41
+ private readonly tree: Tree
42
+ private readonly discovery: Discovery
43
+ private readonly origins: Set<string>
44
+
45
+ public constructor (options: MCP, tree: Tree) {
46
+ this.options = options
47
+ this.tree = tree
48
+ this.discovery = discovery(options)
49
+ this.origins = new Set(options.origins ?? [])
50
+ }
51
+
52
+ public async process (context: http.Context,
53
+ route: http.Processor): Promise<http.OutgoingMessage> {
54
+ if (context.request.method !== 'POST')
55
+ throw new http.MethodNotAllowed(new Headers({ allow: 'POST' }))
56
+
57
+ this.admit(context)
58
+
59
+ const message = await this.read(context)
60
+ const version = this.version(context, message)
61
+ const modern = version === MODERN
62
+
63
+ if (modern)
64
+ this.mirrored(context, message)
65
+
66
+ const result = await this.answer({ context, route, tree: this.tree }, message, modern)
67
+
68
+ // a notification is answered by not answering, and there is nothing here to remember
69
+ if (message.id === undefined)
70
+ return { status: ACCEPTED }
71
+
72
+ return {
73
+ status: OK,
74
+ body: { jsonrpc: JSONRPC, id: message.id, result },
75
+ headers: new Headers({ 'cache-control': 'no-store' })
76
+ }
77
+ }
78
+
79
+ /** Who may reach the endpoint at all, before anything it carries is read. */
80
+ private admit (context: http.Context): void {
81
+ const origin = context.request.headers.origin
82
+
83
+ // the revision requires this against DNS rebinding; a request without one is no browser's
84
+ if (origin !== undefined && !this.origins.has(origin))
85
+ throw new http.Forbidden('Origin is not allowed')
86
+
87
+ if (this.options.anonymous === true)
88
+ return
89
+
90
+ if ((context as { identity?: unknown }).identity == null)
91
+ throw new http.Unauthorized()
92
+ }
93
+
94
+ private async answer (scope: Scope, message: Message, modern: boolean): Promise<unknown> {
95
+ const params = message.params ?? {}
96
+
97
+ switch (message.method) {
98
+ case 'server/discover':
99
+ return this.complete(this.discovery.modern, modern, DISCOVERY_CACHE)
100
+
101
+ case 'tools/list':
102
+ return this.complete({ tools: await list(this.tree, scope.context) }, modern, TOOLS_CACHE)
103
+
104
+ case 'tools/call':
105
+ return this.complete(await this.tool(scope, params), modern)
106
+
107
+ // what a client of an earlier revision opens with; no session is made and none is named
108
+ case 'initialize':
109
+ return this.discovery.legacy(declared(params))
110
+
111
+ case 'notifications/initialized':
112
+ return null
113
+
114
+ case 'ping':
115
+ return {}
116
+
117
+ default:
118
+ throw new http.NotFound(response(message.id ?? null,
119
+ failure(METHOD_NOT_FOUND, `'${message.method}' is not a method this server answers`)))
120
+ }
121
+ }
122
+
123
+ private async tool (scope: Scope, params: Params): Promise<object> {
124
+ const named = params.name
125
+
126
+ if (typeof named !== 'string')
127
+ throw new http.BadRequest(response(null,
128
+ failure(INVALID_PARAMS, '`tools/call` states the tool it calls by name')))
129
+
130
+ const args = params.arguments ?? {}
131
+
132
+ if (typeof args !== 'object' || args === null || Array.isArray(args))
133
+ throw new http.BadRequest(response(null,
134
+ failure(INVALID_PARAMS, '`arguments` must be an object')))
135
+
136
+ return await console.span({ name: named },
137
+ async () => await call(scope, named, args as Params))
138
+ }
139
+
140
+ /**
141
+ * Every result of the modern revision says what kind it is, and who answered it. Where the
142
+ * revision names the operation as one whose result may be held, it says that too, and must.
143
+ */
144
+ private complete (result: object, modern: boolean, cache?: Cache): object {
145
+ return modern
146
+ ? { ...result, ...cache, resultType: 'complete', _meta: { [SERVER_INFO]: this.serverInfo() } }
147
+ : result
148
+ }
149
+
150
+ private serverInfo (): unknown {
151
+ return (this.discovery.modern as { _meta: Record<string, unknown> })._meta[SERVER_INFO]
152
+ }
153
+
154
+ /**
155
+ * Which revision this request is of. `initialize` is one by itself; otherwise the header
156
+ * says, and a request that names none is of a revision that did not send one.
157
+ */
158
+ private version (context: http.Context, message: Message): string {
159
+ if (message.method === 'initialize')
160
+ return LEGACY
161
+
162
+ const header = context.request.headers['mcp-protocol-version']
163
+ const stated = declared(message.params ?? {})
164
+
165
+ if (header !== undefined && stated !== undefined && header !== stated)
166
+ throw new http.BadRequest(response(message.id ?? null, failure(HEADER_MISMATCH,
167
+ `'MCP-Protocol-Version' says '${String(header)}' and the body says '${stated}'`)))
168
+
169
+ const value = (header as string | undefined) ?? stated
170
+
171
+ if (value === undefined)
172
+ return LEGACY
173
+
174
+ if (!VERSIONS.includes(value))
175
+ throw new http.BadRequest(response(message.id ?? null,
176
+ failure(UNSUPPORTED_VERSION, 'Unsupported protocol version',
177
+ { supported: VERSIONS, requested: value })))
178
+
179
+ return value
180
+ }
181
+
182
+ /**
183
+ * What the modern revision mirrors into headers, so that what routes a request and what
184
+ * answers it cannot be told two different things.
185
+ */
186
+ private mirrored (context: http.Context, message: Message): void {
187
+ const meta = metadata(message.params ?? {})
188
+
189
+ if (meta?.[PROTOCOL_VERSION] === undefined || meta[CLIENT_CAPABILITIES] === undefined)
190
+ throw new http.BadRequest(response(message.id ?? null, failure(INVALID_PARAMS,
191
+ `'_meta' states '${PROTOCOL_VERSION}' and '${CLIENT_CAPABILITIES}'`)))
192
+
193
+ const id = message.id ?? null
194
+
195
+ mirrors(context, { id, header: 'mcp-method', value: message.method })
196
+
197
+ if (message.method === 'tools/call')
198
+ mirrors(context, { id, header: 'mcp-name', value: (message.params ?? {}).name })
199
+ }
200
+
201
+ /** A body the decoder refuses is a parse error; a media type it does not know is not. */
202
+ private async read (context: http.Context): Promise<Message> {
203
+ let body: unknown
204
+
205
+ try {
206
+ body = await context.body()
207
+ } catch (exception) {
208
+ if (exception instanceof http.BadRequest)
209
+ throw new http.BadRequest(response(null, failure(PARSE, 'Parse error')))
210
+
211
+ throw exception
212
+ }
213
+
214
+ if (typeof body !== 'object' || body === null || Array.isArray(body) ||
215
+ (body as Message).jsonrpc !== JSONRPC || typeof (body as Message).method !== 'string')
216
+ throw new http.BadRequest(response(null,
217
+ failure(INVALID_REQUEST, 'A request carries one JSON-RPC message')))
218
+
219
+ return body as Message
220
+ }
221
+ }
222
+
223
+ /** What a header says must be what the body says, or what routes and what answers differ. */
224
+ function mirrors (context: http.Context, mirror: Mirror): void {
225
+ const { id, header, value } = mirror
226
+ const stated = context.request.headers[header]
227
+
228
+ if (stated === undefined)
229
+ throw new http.BadRequest(response(id, failure(HEADER_MISMATCH, `'${header}' is required`)))
230
+
231
+ if (decode(String(stated)) !== value)
232
+ throw new http.BadRequest(response(id, failure(HEADER_MISMATCH,
233
+ `'${header}' says '${String(stated)}' and the body says '${String(value)}'`)))
234
+ }
235
+
236
+ interface Mirror {
237
+ id: string | number | null
238
+ header: string
239
+ value: unknown
240
+ }
241
+
242
+ function metadata (params: Params): Record<string, unknown> | undefined {
243
+ const meta = params._meta
244
+
245
+ return typeof meta === 'object' && meta !== null
246
+ ? meta as Record<string, unknown>
247
+ : undefined
248
+ }
249
+
250
+ function declared (params: Params): string | undefined {
251
+ const stated = metadata(params)?.[PROTOCOL_VERSION]
252
+
253
+ return typeof stated === 'string' ? stated : undefined
254
+ }
255
+
256
+ /** What a header value that could not be written as ASCII was encoded as. */
257
+ function decode (value: string): string {
258
+ if (!value.startsWith(SENTINEL) || !value.endsWith(TERMINATOR))
259
+ return value
260
+
261
+ const encoded = value.slice(SENTINEL.length, -TERMINATOR.length)
262
+
263
+ return Buffer.from(encoded, 'base64').toString('utf8')
264
+ }
265
+
266
+ /** A tool list is what the tree holds, which stands until a branch of it expires. */
267
+ const TOOLS_CACHE: Cache = { ttlMs: BRANCH_TTL, cacheScope: 'private' }
268
+
269
+ /** What the annotation says, which is the same for every caller until the application is redeployed. */
270
+ const DISCOVERY_CACHE: Cache = { ttlMs: BRANCH_TTL, cacheScope: 'public' }
271
+
272
+ const OK = 200
273
+ const ACCEPTED = 202
274
+ const SENTINEL = '=?base64?'
275
+ const TERMINATOR = '?='
@@ -0,0 +1,52 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { LEGACY, MODERN, SERVER_INFO, VERSIONS } from './types.js'
3
+ import type { MCP } from '../Annotation.js'
4
+
5
+ /**
6
+ * What a client is told before it calls anything: the revisions served, what is served, and
7
+ * who serves it. It is a function of the annotation alone, so it is built once and answered
8
+ * as it is.
9
+ */
10
+ export interface Discovery {
11
+ /** `server/discover`, which the modern revision has replaced the handshake with. */
12
+ modern: object
13
+
14
+ /** `initialize`, in the shape a client of an earlier revision reads. */
15
+ legacy: (offered: string | undefined) => object
16
+ }
17
+
18
+ export function discovery (options: MCP): Discovery {
19
+ const info = { name: options.name, version: VERSION }
20
+
21
+ // `listChanged` is a stream a client holds open, and this endpoint holds none
22
+ const capabilities = { tools: {} }
23
+
24
+ const modern: Record<string, unknown> = {
25
+ supportedVersions: VERSIONS,
26
+ capabilities,
27
+ _meta: { [SERVER_INFO]: info }
28
+ }
29
+
30
+ if (options.instructions !== undefined)
31
+ modern.instructions = options.instructions
32
+
33
+ function legacy (offered: string | undefined): object {
34
+ const value: Record<string, unknown> = {
35
+ // what the client asked for where that is served, and the newest handshake otherwise
36
+ protocolVersion: offered !== undefined && offered !== MODERN ? offered : LEGACY,
37
+ capabilities,
38
+ serverInfo: info
39
+ }
40
+
41
+ if (options.instructions !== undefined)
42
+ value.instructions = options.instructions
43
+
44
+ return value
45
+ }
46
+
47
+ return { modern, legacy }
48
+ }
49
+
50
+ /** What this gateway is, which is what answers however an application names itself. */
51
+ const VERSION: string = JSON.parse(
52
+ readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version