@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
@@ -2,18 +2,36 @@ import type { Parameter } from './Match.js'
2
2
  import type * as syntax from './syntax/index.js'
3
3
  import type { Context, OutgoingMessage, Options } from '../HTTP/index.js'
4
4
  import type { Output } from '../io.js'
5
+ import type { Introspection } from '../Introspection.js'
5
6
  import type { extensions } from '@toa.io/core'
6
7
 
7
8
  type Host = extensions.Host
8
9
 
9
10
  export interface Directives {
10
- preflight: (context: Context, parameters: Parameter[]) => Promise<Output>
11
+ /**
12
+ * The directives of one family on this method, or nothing where it declares none of it.
13
+ * For a consumer of a declaration rather than of a stage: what a method is published as
14
+ * is stated on the route, and read where the publishing happens.
15
+ */
16
+ declared: <T>(family: string) => T[] | undefined
17
+
18
+ precall: (context: Context, parameters: Parameter[]) => Promise<Output>
19
+
20
+ /** What this route's directives make of what its method says about itself. */
21
+ explain: (context: Context, introspection: Introspection) => Promise<Introspection | null>
11
22
  settle: (context: Context, response: OutgoingMessage) => Promise<void>
12
23
  dispose: () => void
13
24
  }
14
25
 
15
26
  export interface DirectiveFactory {
16
27
  create: (directives: syntax.Directive[], route: string) => Directives
28
+
29
+ /** Runs every family's `preflight`, which is request-scoped and needs no node. */
30
+ preflight: (context: Context) => Promise<void>
31
+
32
+ /** Runs every family's `depart`, the counterpart of `preflight`. */
33
+ depart: (context: Context, response: OutgoingMessage) => Promise<void>
34
+
17
35
  dispose: () => void
18
36
  }
19
37
 
@@ -43,13 +61,45 @@ export interface DirectiveFamily<TDirective = any, TExtension = any> {
43
61
  */
44
62
  arrange?: (directives: TDirective[]) => void
45
63
 
46
- preflight?: (directives: TDirective[],
64
+ /**
65
+ * Request-scoped, before anything is routed. It takes no directives: no node is known
66
+ * yet, and a request that carries several calls has no single node at all. What a
67
+ * directive declares is call-scoped by definition, so only what a family does on its
68
+ * own behalf — authenticating a credential — belongs here. It answers nothing: a stage
69
+ * that runs before a route is known has no reply to make, and refuses by throwing.
70
+ */
71
+ preflight?: (request: Context & TExtension) => void | Promise<void>
72
+
73
+ /** Call-scoped, with what the node declares. Runs once per call. */
74
+ precall?: (directives: TDirective[],
47
75
  request: Context & TExtension,
48
76
  parameters: Parameter[]) => Output | Promise<Output>
49
77
 
78
+ /**
79
+ * What this family's directives make of what the method says about itself, which is
80
+ * what `OPTIONS` answers and what a tool is described by. `null` refuses: the method
81
+ * is not reachable by this caller, and is not described at all.
82
+ *
83
+ * There is no request here — no route variable has a value and no body has arrived, which
84
+ * is why no parameters are passed — so a directive that can only tell from one hands back
85
+ * what it was given.
86
+ */
87
+ explain?: (directives: TDirective[],
88
+ request: Context & TExtension,
89
+ introspection: Introspection) => Introspection | null | Promise<Introspection | null>
90
+
91
+ /** Call-scoped, on the message that call produced. */
50
92
  settle?: (directives: TDirective[],
51
93
  request: Context & TExtension,
52
94
  response: OutgoingMessage) => void | Promise<void>
53
95
 
96
+ /**
97
+ * Request-scoped, on the message going back — the counterpart of `preflight`, and
98
+ * likewise without directives. A reply the whole request carries, such as a re-issued
99
+ * credential, is written here rather than by a call that would not own it.
100
+ */
101
+ depart?: (request: Context & TExtension,
102
+ response: OutgoingMessage) => void | Promise<void>
103
+
54
104
  dispose?: (directives: TDirective[]) => void
55
105
  }
@@ -2,11 +2,12 @@ import { type Context } from './Context.js'
2
2
  import type * as http from '../HTTP/index.js'
3
3
  import type * as syntax from './syntax/index.js'
4
4
  import type * as RTD from './index.js'
5
+ import type { Introspection } from '../Introspection.js'
5
6
 
6
7
  export interface Endpoint {
7
8
  call: (context: http.Context, parameters: RTD.Parameter[]) => Promise<http.OutgoingMessage>
8
9
 
9
- explain: (parameters: RTD.Parameter[]) => Promise<unknown>
10
+ explain: (parameters: RTD.Parameter[]) => Promise<Introspection>
10
11
 
11
12
  close: () => Promise<void>
12
13
  }
@@ -1,29 +1,32 @@
1
1
  import type { Parameter } from './Match.js'
2
2
  import type { Endpoint } from './Endpoint.js'
3
3
  import type { Directives } from './Directives.js'
4
+ import type { Context } from '../HTTP/index.js'
5
+ import { order } from '../Introspection.js'
6
+ import type { Introspection } from '../Introspection.js'
4
7
 
5
8
  export class Method {
6
9
  public readonly endpoint: Endpoint | null
7
10
  public readonly directives: Directives
8
- private introspection: unknown | null = null
9
- private introspecting: Promise<unknown> | null = null
10
11
 
11
12
  public constructor (endpoint: Endpoint | null, directives: Directives) {
12
13
  this.endpoint = endpoint
13
14
  this.directives = directives
14
15
  }
15
16
 
16
- public async explain (parameters: Parameter[]): Promise<unknown> {
17
- if (this.introspection !== null)
18
- return this.introspection
17
+ /**
18
+ * What this method says about itself, as its directives leave it, or nothing where they
19
+ * refuse this caller. A method of no endpoint — one a directive answers on its own —
20
+ * states nothing of its own, and its directives still have their say.
21
+ */
22
+ public async explain (context: Context, parameters: Parameter[]): Promise<Introspection | null> {
23
+ const introspection = this.endpoint === null
24
+ ? {}
25
+ : await this.endpoint.explain(parameters)
19
26
 
20
- if (this.introspecting === null)
21
- // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
22
- this.introspecting = this.endpoint?.explain(parameters)!
27
+ const described = await this.directives.explain(context, introspection)
23
28
 
24
- this.introspection = await this.introspecting
25
-
26
- return this.introspection
29
+ return described === null ? null : order(described)
27
30
  }
28
31
 
29
32
  public async close (): Promise<void> {
@@ -1,6 +1,9 @@
1
1
  import { type Route } from './Route.js'
2
- import { type Methods } from './Method.js'
2
+ import { type Method, type Methods } from './Method.js'
3
3
  import { type Match, type Parameter } from './Match.js'
4
+ import type { Segment } from './segment.js'
5
+ import type { Context } from '../HTTP/index.js'
6
+ import type { Introspection } from '../Introspection.js'
4
7
 
5
8
  export class Node {
6
9
  public intermediate: boolean
@@ -52,14 +55,35 @@ export class Node {
52
55
  this.expiration = expiration
53
56
  }
54
57
 
55
- public async explain (parameters: Parameter[]): Promise<Record<string, unknown>> {
56
- const methods: Record<string, unknown> = {}
58
+ /**
59
+ * Every method under this node, with the template it answers at.
60
+ *
61
+ * An intermediate node is skipped: it is never what a path matches, because its `/` route
62
+ * answers at the same place and is reached instead. The trunk is the exception `match`
63
+ * makes for it — `'/'` answers the trunk itself, whatever it holds.
64
+ */
65
+ public * walk (segments: Segment[], trunk = false): Generator<Mount> {
66
+ if (trunk || !this.intermediate)
67
+ for (const [verb, method] of Object.entries(this.methods))
68
+ yield { segments, verb, method }
69
+
70
+ for (const route of this.routes)
71
+ yield * route.walk(segments)
72
+ }
57
73
 
58
- const explained = Object.entries(this.methods)
59
- .map(async ([verb, method]) =>
60
- (methods[verb] = await method.explain(parameters)))
74
+ /** Every method of this node that this caller may reach, in the order they were declared. */
75
+ public async explain (context: Context,
76
+ parameters: Parameter[]): Promise<Record<string, Introspection>> {
77
+ const entries = Object.entries(this.methods)
61
78
 
62
- await Promise.all(explained)
79
+ const explained = await Promise.all(entries
80
+ .map(async ([, method]) => await method.explain(context, parameters)))
81
+
82
+ const methods: Record<string, Introspection> = {}
83
+
84
+ for (let i = 0; i < entries.length; i++)
85
+ if (explained[i] !== null)
86
+ methods[entries[i][0]] = explained[i]!
63
87
 
64
88
  return methods
65
89
  }
@@ -119,6 +143,13 @@ export class Node {
119
143
  }
120
144
  }
121
145
 
146
+ /** A method, and the route template it is reached by. */
147
+ export interface Mount {
148
+ segments: Segment[]
149
+ verb: string
150
+ method: Method
151
+ }
152
+
122
153
  export interface Properties {
123
154
  protected: boolean
124
155
  forward?: string
@@ -1,6 +1,6 @@
1
1
  import { type Segment } from './segment.js'
2
2
  import { type Match, type Parameter } from './Match.js'
3
- import type { Node } from './Node.js'
3
+ import type { Mount, Node } from './Node.js'
4
4
 
5
5
  export class Route {
6
6
  public readonly root: boolean
@@ -32,10 +32,13 @@ export class Route {
32
32
  return null
33
33
 
34
34
  if (segment.fragment === null && segment.placeholder !== null)
35
- parameters.push({ name: segment.placeholder, value: fragments[i] })
35
+ parameters.push({ name: segment.placeholder, value: decode(fragments[i]) })
36
36
 
37
37
  if (segment.fragment === null && segment.wildcard === true)
38
- parameters.push({ name: '**', value: fragments.slice(this.segments.length - 1).join('/') })
38
+ parameters.push({
39
+ name: '**',
40
+ value: fragments.slice(this.segments.length - 1).map(decode).join('/')
41
+ })
39
42
  }
40
43
 
41
44
  const exact = this.segments.length === fragments.length
@@ -46,6 +49,14 @@ export class Route {
46
49
  return this.matchNested(fragments, parameters)
47
50
  }
48
51
 
52
+ public * walk (prefix: Segment[]): Generator<Mount> {
53
+ // an expired branch is not matched, so nothing under it is reachable to name
54
+ if (Date.now() >= this.node.expiration)
55
+ return
56
+
57
+ yield * this.node.walk(prefix.concat(this.segments))
58
+ }
59
+
49
60
  public equals (route: Route): boolean {
50
61
  if (route.segments.length !== this.segments.length)
51
62
  return false
@@ -67,3 +78,19 @@ export class Route {
67
78
  return this.node.match(fragments, parameters)
68
79
  }
69
80
  }
81
+
82
+ /**
83
+ * What the segment says, rather than how it was written: a value is percent-encoded to
84
+ * survive the path, and an operation reads what a caller meant — a `client_id` that is a
85
+ * URL arrives as one. A literal segment is matched as written, which is how it is declared.
86
+ *
87
+ * An escape that decodes to nothing valid is left as it stands; refusing the route over it
88
+ * would answer `404` to a request whose only fault is its spelling.
89
+ */
90
+ function decode (fragment: string): string {
91
+ try {
92
+ return decodeURIComponent(fragment)
93
+ } catch {
94
+ return fragment
95
+ }
96
+ }
@@ -1,6 +1,8 @@
1
+ import { console } from 'openspan'
2
+ import { refusal, template } from '../RPC/names.js'
1
3
  import { branchTTL, createNode } from './factory.js'
2
4
  import { fragment } from './segment.js'
3
- import type { Node } from './Node.js'
5
+ import type { Mount, Node } from './Node.js'
4
6
  import type { Match } from './Match.js'
5
7
  import type { Context } from './Context.js'
6
8
  import type { DirectiveFactory } from './Directives.js'
@@ -18,6 +20,8 @@ export class Tree {
18
20
  this.directives = directives
19
21
  this.root = node
20
22
  this.trunk = this.createNode(node, PROTECTED)
23
+
24
+ unnameable(this.trunk)
21
25
  }
22
26
 
23
27
  public match (path: string): Match | null {
@@ -32,9 +36,16 @@ export class Tree {
32
36
  return this.trunk.match(fragments)
33
37
  }
34
38
 
39
+ /** Every method in the tree, with the template it answers at. */
40
+ public walk (): Generator<Mount> {
41
+ return this.trunk.walk([], TRUNK)
42
+ }
43
+
35
44
  public merge (node: syntax.Node, extension: unknown): Node[] {
36
45
  const branch = this.createNode(node, !PROTECTED, extension)
37
46
 
47
+ unnameable(branch)
48
+
38
49
  return this.trunk.merge(branch)
39
50
  }
40
51
 
@@ -72,6 +83,30 @@ export class Tree {
72
83
  }
73
84
  }
74
85
 
86
+ /**
87
+ * What is served but cannot be called by name. Said once per route as it is built, because a
88
+ * procedure that is missing is otherwise noticed only by the caller who cannot find it.
89
+ */
90
+ function unnameable (node: Node): void {
91
+ const said = new Set<string>()
92
+
93
+ for (const { segments } of node.walk([], TRUNK)) {
94
+ const segment = refusal(segments)
95
+
96
+ if (segment === null)
97
+ continue
98
+
99
+ const route = template(segments)
100
+
101
+ if (said.has(route))
102
+ continue
103
+
104
+ said.add(route)
105
+
106
+ console.warn('Route cannot be addressed as a procedure', { route, segment })
107
+ }
108
+ }
109
+
75
110
  /**
76
111
  * A branch's routes are relative to wherever it is merged, and the mount point is not
77
112
  * known while it is being built — so the component it came from is what keeps two
@@ -89,3 +124,4 @@ function label (extension: unknown): string {
89
124
  }
90
125
 
91
126
  const PROTECTED = true
127
+ const TRUNK = true
@@ -10,7 +10,7 @@ const endpoints = {} as unknown as EndpointsFactory
10
10
 
11
11
  const directives = {
12
12
  create: () => ({
13
- preflight: async () => null,
13
+ precall: async () => null,
14
14
  settle: async () => undefined,
15
15
  dispose: () => undefined
16
16
  }),
@@ -0,0 +1,110 @@
1
+ import { describe, it, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import { Tree } from './Tree.js'
5
+ import { address, name } from '../RPC/names.js'
6
+ import type { EndpointsFactory } from '../Endpoint.js'
7
+ import type { DirectiveFactory } from './Directives.js'
8
+ import type * as syntax from './syntax/index.js'
9
+
10
+ const endpoints = {} as unknown as EndpointsFactory
11
+
12
+ const directives = {
13
+ create: () => ({
14
+ precall: async () => null,
15
+ settle: async () => undefined,
16
+ dispose: () => undefined
17
+ }),
18
+ dispose: mock.fn()
19
+ } as unknown as DirectiveFactory
20
+
21
+ const node = (path: string, verbs: string[] = [], routes: syntax.Route[] = []): syntax.Route => ({
22
+ path,
23
+ node: {
24
+ routes,
25
+ methods: verbs.map((verb) => ({ verb, directives: [] })),
26
+ directives: []
27
+ }
28
+ })
29
+
30
+ const trunk = (routes: syntax.Route[], verbs: string[] = []): syntax.Node => ({
31
+ routes,
32
+ methods: verbs.map((verb) => ({ verb, directives: [] })),
33
+ directives: []
34
+ })
35
+
36
+ /** What a walk names, which is what a caller of `/.rpc` would write. */
37
+ function names (tree: Tree): string[] {
38
+ return [...tree.walk()].map(({ segments, verb }) => name(segments, verb))
39
+ .filter((named): named is string => named !== null)
40
+ }
41
+
42
+ describe('walk', () => {
43
+ it('should name the trunk by its verb alone', () => {
44
+ const tree = new Tree(trunk([], ['GET']), endpoints, directives)
45
+
46
+ assert.deepEqual(names(tree), ['GET'])
47
+ })
48
+
49
+ it('should name every method of every route', () => {
50
+ const tree = new Tree(trunk([
51
+ node('/pots', ['GET', 'POST'], [node('/:id', ['GET', 'DELETE'])])
52
+ ]), endpoints, directives)
53
+
54
+ assert.deepEqual(names(tree).sort(), [
55
+ 'pots.GET', 'pots.POST', 'pots._id.DELETE', 'pots._id.GET'
56
+ ])
57
+ })
58
+
59
+ it('should walk a branch that was merged', () => {
60
+ const tree = new Tree(trunk([]), endpoints, directives)
61
+
62
+ tree.merge(trunk([node('/pots', ['GET'])]), { namespace: 'default', component: 'pots' })
63
+
64
+ assert.deepEqual(names(tree), ['pots.GET'])
65
+ })
66
+
67
+ it('should name a tail', () => {
68
+ const tree = new Tree(trunk([node('/files', [], [node('/**', ['GET'])])]),
69
+ endpoints, directives)
70
+
71
+ assert.deepEqual(names(tree), ['files.__.GET'])
72
+ })
73
+
74
+ it('should skip an intermediate node, whose route answers in its place', () => {
75
+ const tree = new Tree(trunk([
76
+ // `/posts` is intermediate: `/posts/` is answered by its `/` route, not by itself
77
+ node('/posts', ['PATCH'], [node('/', ['PUT'])])
78
+ ]), endpoints, directives)
79
+
80
+ assert.deepEqual(names(tree), ['posts.PUT'])
81
+ })
82
+
83
+ it('should name nothing where a segment cannot be spelled', () => {
84
+ const tree = new Tree(trunk([node('/v1.0', ['GET']), node('/pots', ['GET'])]),
85
+ endpoints, directives)
86
+
87
+ assert.deepEqual(names(tree), ['pots.GET'])
88
+ })
89
+
90
+ it('should name what the tree then matches', () => {
91
+ const tree = new Tree(trunk([
92
+ node('/pots', ['GET'], [node('/:id', ['GET']), node('/hot', ['GET'])]),
93
+ node('/files', [], [node('/**', ['GET'])])
94
+ ], ['GET']), endpoints, directives)
95
+
96
+ const params = { id: 'a1b2', '**': 'a/b/c' }
97
+
98
+ for (const { segments, verb } of tree.walk()) {
99
+ const named = name(segments, verb)
100
+
101
+ assert.notStrictEqual(named, null, 'every walked method has a name')
102
+
103
+ const { path } = address(named!, params)
104
+ const match = tree.match(path)
105
+
106
+ assert.notStrictEqual(match, null, `'${named!}' resolves to '${path}', which matches`)
107
+ assert.ok(verb in match!.node.methods, `'${named!}' matches a node that answers ${verb}`)
108
+ }
109
+ })
110
+ })
package/source/const.ts CHANGED
@@ -2,3 +2,18 @@ export const BRANCH_TTL = 1_800_000
2
2
 
3
3
  /** The replicas of the gateway decide together, whatever context they serve. */
4
4
  export const ATOM_GROUP = 'exposition'
5
+
6
+ /**
7
+ * Where JSON-RPC is served, for every procedure at once. Pinned rather than configured: a
8
+ * path an application could choose is a path it could collide with a route of its own.
9
+ */
10
+ export const RPC = '/.rpc'
11
+
12
+ /** Calls one request may carry where the annotation does not say. */
13
+ export const BATCH = 32
14
+
15
+ /**
16
+ * Where the Model Context Protocol is served. Pinned for the reason `/.rpc` is: a path an
17
+ * application could choose is a path it could collide with a route of its own.
18
+ */
19
+ export const MCP = '/.mcp'
@@ -70,6 +70,12 @@ export function deployment (_: unknown, annotation?: Annotation): Dependency {
70
70
  if (annotation.oauth !== undefined)
71
71
  properties.oauth = annotation.oauth
72
72
 
73
+ if (annotation.rpc !== undefined)
74
+ properties.rpc = annotation.rpc
75
+
76
+ if (annotation.mcp !== undefined)
77
+ properties.mcp = annotation.mcp
78
+
73
79
  service.variables!.push({
74
80
  name: 'TOA_EXPOSITION_PROPERTIES',
75
81
  value: JSON.stringify(properties)
@@ -86,4 +92,5 @@ export function deployment (_: unknown, annotation?: Annotation): Dependency {
86
92
  return { services: [service] }
87
93
  }
88
94
 
89
- type Properties = Pick<Annotation, 'authorities' | 'debug' | 'protocol' | 'bouncer' | 'ip' | 'oauth'>
95
+ type Properties = Pick<Annotation,
96
+ 'authorities' | 'debug' | 'protocol' | 'bouncer' | 'ip' | 'oauth' | 'rpc' | 'mcp'>
@@ -0,0 +1,38 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import { Anonymous } from './Anonymous.js'
5
+ import type { Context } from './types.js'
6
+
7
+ const context = (headers: Record<string, string>, procedural = false): Context =>
8
+ ({ request: { headers }, procedural }) as unknown as Context
9
+
10
+ describe('anonymous', () => {
11
+ it('should admit a request that presents nothing', () => {
12
+ assert.equal(new Anonymous(true).authorize(null, context({})), true)
13
+ })
14
+
15
+ it('should refuse a request that presents a credential', () => {
16
+ // it would make the reply uncacheable, which is the whole of the rule
17
+ assert.equal(new Anonymous(true).authorize(null, context({ authorization: 'Token x' })), false)
18
+ })
19
+
20
+ it('should admit a procedure whatever the request presented', () => {
21
+ // what a procedure answers is a value in an envelope, and the envelope is `no-store`
22
+ const procedural = context({ authorization: 'Token x' }, true)
23
+
24
+ assert.equal(new Anonymous(true).authorize(null, procedural), true)
25
+ })
26
+
27
+ it('should refuse where it admits nobody', () => {
28
+ assert.equal(new Anonymous(false).authorize(null, context({})), false)
29
+ assert.equal(new Anonymous(false).authorize(null, context({}, true)), false)
30
+ })
31
+
32
+ it('should describe a method as it authorizes one', () => {
33
+ const directive = new Anonymous(true)
34
+
35
+ assert.equal(directive.admits(null, context({ authorization: 'Token x' })), false)
36
+ assert.equal(directive.admits(null, context({ authorization: 'Token x' }, true)), true)
37
+ })
38
+ })
@@ -7,9 +7,21 @@ export class Anonymous implements Directive {
7
7
  this.allow = allow
8
8
  }
9
9
 
10
+ /**
11
+ * A credential refuses, because it would make the reply uncacheable — which is the whole
12
+ * of the rule, and none of it applies to a procedure: what a procedure answers is a value
13
+ * in an envelope, and the envelope is the one thing that is cached or not.
14
+ */
10
15
  public authorize (_: any, context: Context): boolean {
16
+ if (context.procedural)
17
+ return this.allow
18
+
11
19
  return 'authorization' in context.request.headers
12
20
  ? false
13
21
  : this.allow
14
22
  }
23
+
24
+ public admits (_: any, context: Context): boolean {
25
+ return this.authorize(_, context)
26
+ }
15
27
  }
@@ -10,4 +10,8 @@ export class Anyone implements Directive {
10
10
  public authorize (_: any, context: Context): boolean {
11
11
  return context.identity !== null && this.allow
12
12
  }
13
+
14
+ public admits (_: any, context: Context): boolean {
15
+ return this.authorize(_, context)
16
+ }
13
17
  }
@@ -21,6 +21,7 @@ import { ATOM_GROUP } from '../../const.js'
21
21
  import { Quotas, Sync } from '../io/lib/throttle/index.js'
22
22
  import { Keys } from '../io/lib/throttle/Keys.js'
23
23
  import type { Output } from '../../io.js'
24
+ import type { Introspection } from '../../Introspection.js'
24
25
  import type { Component } from '@toa.io/core'
25
26
  import type { Remotes } from '../../Remotes.js'
26
27
  import type { Parameter, DirectiveFamily } from '../../RTD/index.js'
@@ -100,11 +101,18 @@ export class Authorization implements DirectiveFamily<Directive, Extension> {
100
101
  directives.sort((a, b) => (a.priority ?? 1) - (b.priority ?? 1))
101
102
  }
102
103
 
103
- public async preflight (directives: Directive[],
104
- context: Context,
105
- parameters: Parameter[]): Promise<Output> {
104
+ /**
105
+ * Authentication: who the credential names, if one is presented. A credential belongs to
106
+ * the request, so it is read once however many calls the request carries.
107
+ */
108
+ public async preflight (context: Context): Promise<void> {
106
109
  context.identity = await this.resolve(context)
110
+ }
107
111
 
112
+ /** Authorization: whether that identity may make this call, which every call asks anew. */
113
+ public async precall (directives: Directive[],
114
+ context: Context,
115
+ parameters: Parameter[]): Promise<Output> {
108
116
  for (const directive of directives) {
109
117
  const allow = await directive.authorize(context.identity, context, parameters)
110
118
 
@@ -121,12 +129,63 @@ export class Authorization implements DirectiveFamily<Directive, Extension> {
121
129
  throw new http.Forbidden()
122
130
  }
123
131
 
132
+ /**
133
+ * The same disjunction as `precall`, over what can be told without a request. A method no
134
+ * directive admits, and none is undecided about, is not this caller's to be told about —
135
+ * `null` takes it out of the answer.
136
+ *
137
+ * A permission is matched against a path, and a description is not a request to one, so
138
+ * `permits` has no say here. The call it describes is still checked, which is where a
139
+ * token's permissions belong.
140
+ *
141
+ * A method that is described is then described by each of them, which is a separate pass:
142
+ * admission is a disjunction and stops at the first that admits, while what the directives
143
+ * fill is not any one of them's to state alone.
144
+ */
145
+ public async explain (directives: Directive[], context: Context,
146
+ introspection: Introspection): Promise<Introspection | null> {
147
+ let untold = false
148
+ let admitted = false
149
+
150
+ for (const directive of directives) {
151
+ const admits = await directive.admits?.(context.identity, context)
152
+
153
+ if (admits === undefined) {
154
+ untold = true
155
+
156
+ continue
157
+ }
158
+
159
+ if (admits) {
160
+ admitted = true
161
+
162
+ break
163
+ }
164
+ }
165
+
166
+ if (!admitted && !untold)
167
+ return null
168
+
169
+ // whichever of them admitted, a property any of them fills from the identity is filled
170
+ // from the identity: what a caller sent there would be overwritten or forged
171
+ for (const directive of directives)
172
+ introspection = directive.describe?.(introspection) ?? introspection
173
+
174
+ return introspection
175
+ }
176
+
124
177
  public async settle (directives: Directive[],
125
178
  context: Context,
126
179
  response: http.OutgoingMessage): Promise<void> {
127
180
  await Promise.all(directives.map(async (directive) =>
128
181
  directive.settle?.(context, response)))
182
+ }
129
183
 
184
+ /**
185
+ * Re-issuing a credential, and refusing a ban, are the request's business: the header
186
+ * carries one token however many calls were made, and a ban refuses all of them.
187
+ */
188
+ public async depart (context: Context, response: http.OutgoingMessage): Promise<void> {
130
189
  const identity = context.identity
131
190
 
132
191
  if (identity === null)