@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
@@ -0,0 +1,130 @@
1
+ import { console } from 'openspan'
2
+ import * as http from '../HTTP/index.js'
3
+ import * as schemas from '../schemas.js'
4
+ import { BATCH } from '../const.js'
5
+ import { address, split } from './names.js'
6
+ import { fork } from './Context.js'
7
+ import { BATCH_TOO_LARGE, INVALID_REQUEST, PARSE, failure, of, response } from './errors.js'
8
+ import { VERSION, type Call, type Response } from './types.js'
9
+ import type { RPC } from '../Annotation.js'
10
+
11
+ /**
12
+ * JSON-RPC, as the calls a request carries.
13
+ *
14
+ * It clones the context per call and hands each clone back to the gateway: it holds no
15
+ * tree, no index and no knowledge of routing. Whether a name resolves, what it resolves
16
+ * to, and what the directives of that route do are answered by the same `route` an
17
+ * ordinary request goes through.
18
+ */
19
+ export class Dispatcher {
20
+ private readonly batch: number
21
+
22
+ public constructor (options: RPC) {
23
+ this.batch = options.batch ?? BATCH
24
+ }
25
+
26
+ public async dispatch (context: http.Context,
27
+ route: http.Processor): Promise<http.OutgoingMessage> {
28
+ if (context.request.method !== 'POST')
29
+ throw new http.MethodNotAllowed(new Headers({ allow: 'POST' }))
30
+
31
+ const envelope = await this.read(context)
32
+ const batched = Array.isArray(envelope)
33
+ const calls = batched ? envelope : [envelope]
34
+
35
+ if (calls.length === 0)
36
+ throw new http.BadRequest(response(null,
37
+ failure(INVALID_REQUEST, 'A request carries at least one call')))
38
+
39
+ if (calls.length > this.batch)
40
+ throw new http.BadRequest(response(null,
41
+ failure(BATCH_TOO_LARGE, `A request carries at most ${this.batch} calls`)))
42
+
43
+ const answers: Response[] = []
44
+
45
+ // one after another: a request the caller writes should not become a fan-out they own
46
+ for (const call of calls) {
47
+ const answer = await this.answer(call, context, route)
48
+
49
+ if (answer !== null)
50
+ answers.push(answer)
51
+ }
52
+
53
+ // every call was a notification, and a notification is answered by not answering
54
+ if (answers.length === 0)
55
+ return { status: NO_CONTENT }
56
+
57
+ // a reply assembled from several is not one of them, and is not stored as if it were
58
+ return {
59
+ status: OK,
60
+ body: batched ? answers : answers[0],
61
+ headers: new Headers({ 'cache-control': 'no-store' })
62
+ }
63
+ }
64
+
65
+ private async answer (input: unknown, context: http.Context,
66
+ route: http.Processor): Promise<Response | null> {
67
+ const invalid = schemas.call.fit(input)
68
+
69
+ // it may have carried an id, but nothing about it is trustworthy enough to answer to
70
+ if (invalid !== null)
71
+ return response(null, failure(INVALID_REQUEST, invalid.message))
72
+
73
+ return await this.call(input as Call, context, route)
74
+ }
75
+
76
+ private async call (call: Call, context: http.Context,
77
+ route: http.Processor): Promise<Response | null> {
78
+ const notification = call.id === undefined
79
+
80
+ try {
81
+ const params = call.params ?? {}
82
+ const { path, verb, variables } = address(call.method, params)
83
+ const { query, input } = split(params, variables)
84
+ const clone = fork(context, path, verb, query, input)
85
+
86
+ // one span per call, so what the directives of that call open has somewhere to hang
87
+ const message = await console.span({ name: call.method, attributes: { id: call.id } },
88
+ async () => await route(clone))
89
+
90
+ // what `io:output` restricts, over this call's reply rather than the envelope
91
+ await http.shape(clone, message)
92
+
93
+ if (notification)
94
+ return null
95
+
96
+ return { jsonrpc: VERSION, id: call.id!, result: message.body ?? null }
97
+ } catch (exception) {
98
+ /*
99
+ * A credential belongs to the request. Refusing one call for it would leave the
100
+ * reply a 200, and the challenge that tells a client where to authenticate is
101
+ * attached to a 401 — so the whole envelope is refused instead.
102
+ */
103
+ if (exception instanceof http.Unauthorized)
104
+ throw exception
105
+
106
+ if (notification) {
107
+ console.debug('Notification failed', { method: call.method, error: of(exception) })
108
+
109
+ return null
110
+ }
111
+
112
+ return { jsonrpc: VERSION, id: call.id!, error: of(exception) }
113
+ }
114
+ }
115
+
116
+ /** A body the decoder refuses is a parse error; a media type it does not know is not. */
117
+ private async read (context: http.Context): Promise<unknown> {
118
+ try {
119
+ return await context.body()
120
+ } catch (exception) {
121
+ if (exception instanceof http.BadRequest)
122
+ throw new http.BadRequest(response(null, failure(PARSE, 'Parse error')))
123
+
124
+ throw exception
125
+ }
126
+ }
127
+ }
128
+
129
+ const OK = 200
130
+ const NO_CONTENT = 204
@@ -0,0 +1,52 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import * as http from '../HTTP/index.js'
5
+ import {
6
+ FORBIDDEN, INTERNAL, INVALID_PARAMS, METHOD_NOT_FOUND, REFUSED, of
7
+ } from './errors.js'
8
+
9
+ describe('of', () => {
10
+ it('should read a missing route as a missing method', () => {
11
+ assert.deepEqual(of(new http.NotFound('pots/_id/FETCH names no method')),
12
+ { code: METHOD_NOT_FOUND, message: 'pots/_id/FETCH names no method' })
13
+ })
14
+
15
+ it('should read a verb the node does not declare as a missing method', () => {
16
+ assert.deepEqual(of(new http.MethodNotAllowed()),
17
+ { code: METHOD_NOT_FOUND, message: 'Method not found' })
18
+ })
19
+
20
+ it('should read a refused authorization as forbidden', () => {
21
+ assert.deepEqual(of(new http.Forbidden()), { code: FORBIDDEN, message: 'Forbidden' })
22
+ })
23
+
24
+ it('should read a bad request as invalid params', () => {
25
+ assert.deepEqual(of(new http.BadRequest('Query limit must be between 1 and 100')),
26
+ { code: INVALID_PARAMS, message: 'Query limit must be between 1 and 100' })
27
+ })
28
+
29
+ it('should carry the code an operation refused with', () => {
30
+ const error = Object.assign(new Error(), { code: 'WONT_CREATE', message: 'Volume is out of range' })
31
+
32
+ assert.deepEqual(of(new http.UnprocessableEntity(error)),
33
+ { code: REFUSED, message: 'Volume is out of range', data: { code: 'WONT_CREATE' } })
34
+ })
35
+
36
+ it('should stand the code in for a message the operation did not declare', () => {
37
+ const error = Object.assign(new Error(), { code: 'WONT_CREATE' })
38
+
39
+ assert.deepEqual(of(new http.UnprocessableEntity(error)),
40
+ { code: REFUSED, message: 'WONT_CREATE', data: { code: 'WONT_CREATE' } })
41
+ })
42
+
43
+ it('should say what any other client error was refused with', () => {
44
+ assert.deepEqual(of(new http.Conflict()),
45
+ { code: REFUSED, message: 'Refused', data: { status: 409 } })
46
+ })
47
+
48
+ it('should say nothing of what it did not mean to answer', () => {
49
+ assert.deepEqual(of(new Error('the connection dropped')),
50
+ { code: INTERNAL, message: 'Internal error' })
51
+ })
52
+ })
@@ -0,0 +1,83 @@
1
+ import * as http from '../HTTP/index.js'
2
+ import { VERSION, type Failure, type Response } from './types.js'
3
+
4
+ /*
5
+ * The five the specification fixes (JSON-RPC 2.0 §5.1). A client reads these the same
6
+ * whoever answers.
7
+ */
8
+ export const PARSE = -32700
9
+ export const INVALID_REQUEST = -32600
10
+ export const METHOD_NOT_FOUND = -32601
11
+ export const INVALID_PARAMS = -32602
12
+ export const INTERNAL = -32603
13
+
14
+ /*
15
+ * Ours. The specification reserves -32000 to -32099 for implementation-defined server
16
+ * errors and defines nothing in it, so these mean nothing outside Toa — which is why
17
+ * `REFUSED` carries the operation's own code in `data`.
18
+ */
19
+ export const FORBIDDEN = -32000
20
+ export const REFUSED = -32001
21
+ export const BATCH_TOO_LARGE = -32002
22
+
23
+ export function failure (code: number, message: string, data?: unknown): Failure {
24
+ const value: Failure = { code, message }
25
+
26
+ if (data !== undefined)
27
+ value.data = data
28
+
29
+ return value
30
+ }
31
+
32
+ export function response (id: string | number | null, error: Failure): Response {
33
+ return { jsonrpc: VERSION, id, error }
34
+ }
35
+
36
+ /**
37
+ * What an exception says as a JSON-RPC error.
38
+ *
39
+ * The readable text is `body`, never `message`: `http.Exception` calls `super()` with no
40
+ * argument, so every one of them carries an empty `message`.
41
+ */
42
+ export function of (exception: unknown): Failure {
43
+ if (exception instanceof http.UnprocessableEntity)
44
+ return refusal(exception)
45
+
46
+ if (exception instanceof http.NotFound || exception instanceof http.MethodNotAllowed)
47
+ return failure(METHOD_NOT_FOUND, text(exception, 'Method not found'))
48
+
49
+ if (exception instanceof http.Forbidden)
50
+ return failure(FORBIDDEN, text(exception, 'Forbidden'))
51
+
52
+ if (exception instanceof http.BadRequest)
53
+ return failure(INVALID_PARAMS, text(exception, 'Invalid params'))
54
+
55
+ // a conflict, a precondition, a throttle: the call was refused, and by what is worth saying
56
+ if (exception instanceof http.ClientError)
57
+ return failure(REFUSED, text(exception, 'Refused'), { status: exception.status })
58
+
59
+ return failure(INTERNAL, 'Internal error')
60
+ }
61
+
62
+ /**
63
+ * An operation that declares its errors answers with one rather than throwing, and the
64
+ * reply contract states `{ code, message? }` — the message optional. The number says the
65
+ * operation refused; `data.code` says what it refused with, and is what a caller branches on.
66
+ */
67
+ function refusal (exception: http.UnprocessableEntity): Failure {
68
+ const body = exception.body
69
+
70
+ if (typeof body !== 'object' || body === null || typeof body.code !== 'string')
71
+ return failure(REFUSED, text(exception, 'Refused'))
72
+
73
+ const code = body.code as string
74
+ const message = typeof body.message === 'string' && body.message !== '' ? body.message : code
75
+
76
+ return failure(REFUSED, message, { code })
77
+ }
78
+
79
+ function text (exception: http.Exception, fallback: string): string {
80
+ return typeof exception.body === 'string' && exception.body !== ''
81
+ ? exception.body
82
+ : fallback
83
+ }
@@ -0,0 +1 @@
1
+ export { Dispatcher } from './Dispatcher.js'
@@ -0,0 +1,122 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import * as http from '../HTTP/index.js'
5
+ import { segment } from '../RTD/segment.js'
6
+ import { address, name, refusal } from './names.js'
7
+
8
+ describe('address', () => {
9
+ it('should resolve a name without variables', () => {
10
+ assert.deepEqual(address('pots.GET', {}),
11
+ { path: '/pots/', verb: 'GET', variables: [] })
12
+ })
13
+
14
+ it('should resolve the trunk', () => {
15
+ assert.deepEqual(address('GET', {}),
16
+ { path: '/', verb: 'GET', variables: [] })
17
+ })
18
+
19
+ it('should substitute a variable and report it taken', () => {
20
+ assert.deepEqual(address('pots._id.GET', { id: 'a1b2', title: 'Kettle' }),
21
+ { path: '/pots/a1b2/', verb: 'GET', variables: ['id'] })
22
+ })
23
+
24
+ it('should substitute every variable', () => {
25
+ assert.deepEqual(address('users._user.pots._id.PATCH', { user: 'bob', id: 'a1b2' }),
26
+ { path: '/users/bob/pots/a1b2/', verb: 'PATCH', variables: ['user', 'id'] })
27
+ })
28
+
29
+ it('should let a tail carry separators', () => {
30
+ assert.deepEqual(address('files.__.GET', { '**': 'a/b/c' }),
31
+ { path: '/files/a/b/c/', verb: 'GET', variables: ['**'] })
32
+ })
33
+
34
+ it('should not confuse a trailing literal with a verb', () => {
35
+ assert.deepEqual(address('pots.GET.POST', {}),
36
+ { path: '/pots/GET/', verb: 'POST', variables: [] })
37
+ })
38
+
39
+ it('should refuse a name that states no verb', () => {
40
+ assert.throws(() => address('pots._id', { id: 'a1b2' }), http.NotFound)
41
+ })
42
+
43
+ it('should refuse a verb no method uses', () => {
44
+ assert.throws(() => address('pots.FETCH', {}), http.NotFound)
45
+ })
46
+
47
+ it('should refuse a segment no name can spell', () => {
48
+ assert.throws(() => address('pots/v1.GET', {}), http.NotFound)
49
+ assert.throws(() => address('a_b.GET', {}), http.NotFound)
50
+ assert.throws(() => address('pots..GET', {}), http.NotFound)
51
+ })
52
+
53
+ it('should refuse a variable of no name', () => {
54
+ assert.throws(() => address('pots._.GET', { '': 'a1b2' }), http.NotFound)
55
+ })
56
+
57
+ it('should refuse a missing variable', () => {
58
+ assert.throws(() => address('pots._id.GET', {}), http.BadRequest)
59
+ })
60
+
61
+ it('should refuse a variable that would divide the path', () => {
62
+ assert.throws(() => address('pots._id.GET', { id: 'a/b' }), http.BadRequest)
63
+ assert.throws(() => address('pots._id.GET', { id: 'a?b' }), http.BadRequest)
64
+ assert.throws(() => address('pots._id.GET', { id: 'a#b' }), http.BadRequest)
65
+ })
66
+
67
+ it('should refuse a tail that would end the path', () => {
68
+ assert.throws(() => address('files.__.GET', { '**': 'a?b' }), http.BadRequest)
69
+ })
70
+ })
71
+
72
+ describe('name', () => {
73
+ it('should name the trunk by its verb alone', () => {
74
+ assert.equal(name(segment('/'), 'GET'), 'GET')
75
+ })
76
+
77
+ it('should name a route', () => {
78
+ assert.equal(name(segment('/pots'), 'GET'), 'pots.GET')
79
+ assert.equal(name(segment('/identity/tokens'), 'POST'), 'identity.tokens.POST')
80
+ })
81
+
82
+ it('should mark a variable', () => {
83
+ assert.equal(name(segment('/pots/:id'), 'GET'), 'pots._id.GET')
84
+ assert.equal(name(segment('/identity/tokens/:identity'), 'POST'),
85
+ 'identity.tokens._identity.POST')
86
+ })
87
+
88
+ it('should mark a tail', () => {
89
+ assert.equal(name(segment('/files/**'), 'GET'), 'files.__.GET')
90
+ })
91
+
92
+ it('should keep a hyphen', () => {
93
+ assert.equal(name(segment('/jpeg-or-png'), 'GET'), 'jpeg-or-png.GET')
94
+ })
95
+
96
+ it('should name nothing where a segment cannot be spelled', () => {
97
+ assert.equal(name(segment('/v1.0/pots'), 'GET'), null)
98
+ assert.equal(name(segment('/a_b'), 'GET'), null)
99
+ assert.equal(name(segment('/pots/*'), 'GET'), null)
100
+ assert.equal(name(segment('/messages/:sender-:recipient'), 'GET'), null)
101
+ })
102
+
103
+ it('should round-trip what it names', () => {
104
+ const named = name(segment('/pots/:id'), 'GET')!
105
+
106
+ assert.deepEqual(address(named, { id: 'a1b2' }),
107
+ { path: '/pots/a1b2/', verb: 'GET', variables: ['id'] })
108
+ })
109
+ })
110
+
111
+ describe('refusal', () => {
112
+ it('should name nothing where every segment can be spelled', () => {
113
+ assert.equal(refusal(segment('/pots/:id')), null)
114
+ })
115
+
116
+ it('should name the segment as it was declared', () => {
117
+ assert.equal(refusal(segment('/v1.0/pots')), 'v1.0')
118
+ assert.equal(refusal(segment('/pots/a_b')), 'a_b')
119
+ assert.equal(refusal(segment('/pots/*')), '*')
120
+ assert.equal(refusal(segment('/messages/:sender-:recipient')), ':sender-:recipient')
121
+ })
122
+ })
@@ -0,0 +1,183 @@
1
+ import * as http from '../HTTP/index.js'
2
+ import { verbs } from '../RTD/syntax/index.js'
3
+ import type { Segment } from '../RTD/segment.js'
4
+ import { QUERY, type Params } from './types.js'
5
+
6
+ /**
7
+ * What a name resolves to: the path the call is made at, and the verb it is made with.
8
+ *
9
+ * A name is the route template with its variables marked and the verb appended as a segment
10
+ * of its own — `pots._id.GET`. The revision names the characters a tool's name may hold, and
11
+ * `/` is not among them, so segments are joined by `.` — which a segment cannot hold either,
12
+ * so nothing in a name can be mistaken for anything else, and the verb is always last.
13
+ */
14
+ export interface Address {
15
+ path: string
16
+ verb: string
17
+
18
+ /** the `params` the path took, which are therefore not the operation's input */
19
+ variables: string[]
20
+ }
21
+
22
+ export function address (method: string, params: Params): Address {
23
+ const parts = method.split(SEPARATOR)
24
+ const verb = parts.pop()!
25
+
26
+ if (!verbs.has(verb))
27
+ throw new http.NotFound(`'${method}' names no method`)
28
+
29
+ const variables: string[] = []
30
+ const fragments: string[] = []
31
+
32
+ for (const part of parts) {
33
+ const key = parameter(part)
34
+
35
+ if (key === null) {
36
+ fragments.push(literal(part, method))
37
+
38
+ continue
39
+ }
40
+
41
+ if (part !== TAIL && !NAMEABLE.test(key))
42
+ throw new http.NotFound(`'${method}' names no procedure`)
43
+
44
+ const value = params[key]
45
+
46
+ if (value === undefined || value === null)
47
+ throw new http.BadRequest(`'${method}' requires the parameter '${key}'`)
48
+
49
+ const fragment = String(value)
50
+
51
+ // `__` stands for the rest of the path and may carry separators; a variable is one segment
52
+ if (!(part === TAIL ? TAILED : OPAQUE).test(fragment))
53
+ throw new http.BadRequest(`The parameter '${key}' cannot be a path of its own`)
54
+
55
+ variables.push(key)
56
+ fragments.push(fragment)
57
+ }
58
+
59
+ // a route is matched with its trailing slash, and the trunk is the bare one
60
+ const path = fragments.length === 0 ? '/' : `/${fragments.join('/')}/`
61
+
62
+ return { path, verb, variables }
63
+ }
64
+
65
+ /**
66
+ * What the call carries, as a request carries it: the path took its variables, `query` is
67
+ * the querystring, and the rest is the body.
68
+ */
69
+ export function split (params: Params, variables: string[]): { query?: Params, input?: Params } {
70
+ const input: Params = {}
71
+ let query: Params | undefined
72
+
73
+ for (const [key, value] of Object.entries(params)) {
74
+ if (variables.includes(key))
75
+ continue
76
+
77
+ if (key !== QUERY) {
78
+ input[key] = value
79
+
80
+ continue
81
+ }
82
+
83
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
84
+ throw new http.BadRequest(`'${QUERY}' must be an object`)
85
+
86
+ query = value as Params
87
+ }
88
+
89
+ // an absent body is what a request without one has, and the mapping fills it as it does
90
+ return { query, input: Object.keys(input).length === 0 ? undefined : input }
91
+ }
92
+
93
+ /** The parameter a part reads, or nothing where the part is a literal segment. */
94
+ function parameter (part: string): string | null {
95
+ if (part === TAIL)
96
+ return WILDCARD
97
+
98
+ return part[0] === VARIABLE ? part.slice(1) : null
99
+ }
100
+
101
+ /** A segment a name cannot spell is a segment no name has, so this one names nothing. */
102
+ function literal (part: string, method: string): string {
103
+ if (!NAMEABLE.test(part))
104
+ throw new http.NotFound(`'${method}' names no procedure`)
105
+
106
+ return part
107
+ }
108
+
109
+ /** The name of a method on this route, or nothing where the route has none. */
110
+ export function name (segments: Segment[], verb: string): string | null {
111
+ const parts: string[] = []
112
+
113
+ for (const segment of segments) {
114
+ const part = component(segment)
115
+
116
+ if (part === null)
117
+ return null
118
+
119
+ parts.push(part)
120
+ }
121
+
122
+ parts.push(verb)
123
+
124
+ return parts.join(SEPARATOR)
125
+ }
126
+
127
+ /** The segment that leaves a route unnameable, as it was declared, or nothing where none does. */
128
+ export function refusal (segments: Segment[]): string | null {
129
+ for (const segment of segments)
130
+ if (component(segment) === null)
131
+ return declared(segment)
132
+
133
+ return null
134
+ }
135
+
136
+ function component (segment: Segment): string | null {
137
+ if (segment.fragment !== null)
138
+ return NAMEABLE.test(segment.fragment) ? segment.fragment : null
139
+
140
+ if (segment.wildcard === true)
141
+ return TAIL
142
+
143
+ // it stands for a segment the caller cannot name, so there is nothing to substitute
144
+ if (segment.placeholder === null)
145
+ return null
146
+
147
+ return NAMEABLE.test(segment.placeholder) ? VARIABLE + segment.placeholder : null
148
+ }
149
+
150
+ /** The route as it was declared, which is how a message about it should read. */
151
+ export function template (segments: Segment[]): string {
152
+ return '/' + segments.map(declared).join('/')
153
+ }
154
+
155
+ function declared (segment: Segment): string {
156
+ if (segment.fragment !== null)
157
+ return segment.fragment
158
+
159
+ if (segment.wildcard === true)
160
+ return '**'
161
+
162
+ return segment.placeholder === null ? '*' : ':' + segment.placeholder
163
+ }
164
+
165
+ const SEPARATOR = '.'
166
+ const VARIABLE = '_'
167
+ const TAIL = '__'
168
+
169
+ /** How the RTD names the rest of a path, wherever a parameter of it is read. */
170
+ const WILDCARD = '**'
171
+
172
+ /**
173
+ * What a segment may hold to have a name. `_` is the convention's own, and every other
174
+ * character a client leaves alone is here: a client shows a model the name with the rest
175
+ * turned into `_`, and two names must not become one.
176
+ */
177
+ const NAMEABLE = /^[A-Za-z0-9-]+$/
178
+
179
+ /** A segment ends at what divides or ends a path. */
180
+ const OPAQUE = /^[^/?#]*$/
181
+
182
+ /** A tail is several segments, so it keeps the divider and loses only what ends a path. */
183
+ const TAILED = /^[^?#]*$/
@@ -0,0 +1,34 @@
1
+ /** The version every call and every response states. */
2
+ export const VERSION = '2.0'
3
+
4
+ /**
5
+ * The member `params` reserves for what a querystring would carry. An operation's input is
6
+ * free to have an `id` or a `limit` of its own, so the two cannot share one object.
7
+ */
8
+ export const QUERY = 'query'
9
+
10
+ export type Params = Record<string, unknown>
11
+
12
+ export interface Call {
13
+ jsonrpc: string
14
+ method: string
15
+ params?: Params
16
+
17
+ /** Absent makes this a notification: it runs, and nothing is returned for it. */
18
+ id?: string | number
19
+ }
20
+
21
+ export interface Response {
22
+ jsonrpc: string
23
+
24
+ /** `null` where the request was not readable enough to carry one. */
25
+ id: string | number | null
26
+ result?: unknown
27
+ error?: Failure
28
+ }
29
+
30
+ export interface Failure {
31
+ code: number
32
+ message: string
33
+ data?: unknown
34
+ }