@toa.io/extensions.exposition 1.0.0-alpha.3 → 1.0.0-alpha.31

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 (431) hide show
  1. package/components/context.toa.yaml +2 -2
  2. package/components/identity.bans/manifest.toa.yaml +15 -6
  3. package/components/identity.bans/operations/transit.d.ts +14 -0
  4. package/components/identity.bans/operations/transit.js +11 -0
  5. package/components/identity.bans/operations/transit.js.map +1 -0
  6. package/components/identity.bans/operations/tsconfig.tsbuildinfo +1 -0
  7. package/components/identity.bans/source/transit.ts +21 -0
  8. package/components/identity.bans/tsconfig.json +9 -0
  9. package/components/identity.basic/manifest.toa.yaml +21 -8
  10. package/components/identity.basic/operations/authenticate.d.ts +5 -1
  11. package/components/identity.basic/operations/authenticate.js +5 -2
  12. package/components/identity.basic/operations/authenticate.js.map +1 -1
  13. package/components/identity.basic/operations/incept.d.ts +12 -0
  14. package/components/identity.basic/operations/incept.js +20 -0
  15. package/components/identity.basic/operations/incept.js.map +1 -0
  16. package/components/identity.basic/operations/transit.d.ts +3 -3
  17. package/components/identity.basic/operations/transit.js +5 -3
  18. package/components/identity.basic/operations/transit.js.map +1 -1
  19. package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -1
  20. package/components/identity.basic/operations/types.d.ts +2 -0
  21. package/components/identity.basic/source/authenticate.ts +16 -5
  22. package/components/identity.basic/source/incept.ts +32 -0
  23. package/components/identity.basic/source/transit.ts +7 -5
  24. package/components/identity.basic/source/types.ts +2 -0
  25. package/components/identity.federation/manifest.toa.yaml +28 -17
  26. package/components/identity.federation/operations/authenticate.d.ts +2 -2
  27. package/components/identity.federation/operations/authenticate.js +6 -5
  28. package/components/identity.federation/operations/authenticate.js.map +1 -1
  29. package/components/identity.federation/operations/incept.d.ts +11 -0
  30. package/components/identity.federation/operations/{create.js → incept.js} +6 -7
  31. package/components/identity.federation/operations/incept.js.map +1 -0
  32. package/components/identity.federation/operations/lib/jwt.d.ts +4 -5
  33. package/components/identity.federation/operations/lib/jwt.js +3 -3
  34. package/components/identity.federation/operations/lib/jwt.js.map +1 -1
  35. package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
  36. package/components/identity.federation/operations/types/configuration.d.ts +15 -0
  37. package/components/identity.federation/operations/types/configuration.js +3 -0
  38. package/components/identity.federation/operations/types/configuration.js.map +1 -0
  39. package/components/identity.federation/operations/{types.d.ts → types/context.d.ts} +8 -3
  40. package/components/identity.federation/operations/types/context.js +3 -0
  41. package/components/identity.federation/operations/types/context.js.map +1 -0
  42. package/components/identity.federation/operations/types/entity.d.ts +6 -0
  43. package/components/identity.federation/operations/{types.js → types/entity.js} +1 -1
  44. package/components/identity.federation/operations/types/entity.js.map +1 -0
  45. package/components/identity.federation/operations/types/index.d.ts +3 -0
  46. package/components/identity.federation/operations/types/index.js +20 -0
  47. package/components/identity.federation/operations/types/index.js.map +1 -0
  48. package/components/identity.federation/source/authenticate.ts +10 -9
  49. package/components/identity.federation/source/{create.ts → incept.ts} +10 -9
  50. package/components/identity.federation/source/lib/jwt.test.ts +2 -2
  51. package/components/identity.federation/source/lib/jwt.ts +7 -8
  52. package/components/identity.federation/source/types/configuration.ts +16 -0
  53. package/components/identity.federation/source/{types.ts → types/context.ts} +9 -4
  54. package/components/identity.federation/source/types/entity.ts +6 -0
  55. package/components/identity.federation/source/types/index.ts +3 -0
  56. package/components/identity.federation/tsconfig.json +2 -2
  57. package/components/identity.roles/manifest.toa.yaml +18 -5
  58. package/components/identity.roles/operations/grant.d.ts +10 -0
  59. package/components/identity.roles/operations/grant.js +21 -0
  60. package/components/identity.roles/operations/grant.js.map +1 -0
  61. package/components/identity.roles/operations/lib/Entity.d.ts +5 -0
  62. package/components/identity.roles/operations/lib/Entity.js +3 -0
  63. package/components/identity.roles/operations/lib/Entity.js.map +1 -0
  64. package/components/identity.roles/operations/list.d.ts +1 -4
  65. package/components/identity.roles/operations/list.js.map +1 -1
  66. package/components/identity.roles/operations/principal.d.ts +4 -6
  67. package/components/identity.roles/operations/principal.js +6 -1
  68. package/components/identity.roles/operations/principal.js.map +1 -1
  69. package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
  70. package/components/identity.roles/source/grant.ts +32 -0
  71. package/components/identity.roles/source/lib/Entity.ts +5 -0
  72. package/components/identity.roles/source/list.ts +2 -4
  73. package/components/identity.roles/source/principal.ts +10 -8
  74. package/components/identity.tokens/manifest.toa.yaml +19 -4
  75. package/components/identity.tokens/operations/authenticate.d.ts +2 -2
  76. package/components/identity.tokens/operations/authenticate.js +10 -4
  77. package/components/identity.tokens/operations/authenticate.js.map +1 -1
  78. package/components/identity.tokens/operations/decrypt.js +1 -0
  79. package/components/identity.tokens/operations/decrypt.js.map +1 -1
  80. package/components/identity.tokens/operations/encrypt.js +5 -1
  81. package/components/identity.tokens/operations/encrypt.js.map +1 -1
  82. package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
  83. package/components/identity.tokens/operations/types.d.ts +8 -2
  84. package/components/identity.tokens/receivers/identity.bans.created.js +3 -0
  85. package/components/identity.tokens/source/authenticate.test.ts +11 -4
  86. package/components/identity.tokens/source/authenticate.ts +12 -5
  87. package/components/identity.tokens/source/decrypt.test.ts +5 -3
  88. package/components/identity.tokens/source/decrypt.ts +9 -8
  89. package/components/identity.tokens/source/encrypt.test.ts +26 -2
  90. package/components/identity.tokens/source/encrypt.ts +5 -1
  91. package/components/identity.tokens/source/types.ts +9 -2
  92. package/components/octets.storage/manifest.toa.yaml +0 -6
  93. package/components/octets.storage/operations/store.js +1 -1
  94. package/documentation/access.md +27 -16
  95. package/documentation/authorities.md +53 -0
  96. package/documentation/cache.md +8 -1
  97. package/documentation/components.md +52 -27
  98. package/documentation/identity.md +17 -22
  99. package/documentation/io.md +56 -0
  100. package/documentation/protocol.md +3 -0
  101. package/documentation/query.md +57 -8
  102. package/documentation/require.md +15 -0
  103. package/documentation/tree.md +22 -4
  104. package/documentation/vary.md +14 -14
  105. package/entity.json +0 -0
  106. package/features/access.feature +83 -56
  107. package/features/annotation.feature +2 -0
  108. package/features/authorities.basic.feature +141 -0
  109. package/features/authorities.feature +32 -0
  110. package/features/authorities.federation.feature +99 -0
  111. package/features/authorities.tokens.feature +118 -0
  112. package/features/body.feature +5 -1
  113. package/features/cache.feature +78 -5
  114. package/features/cors.feature +6 -2
  115. package/features/debug.feature +34 -0
  116. package/features/directives.feature +5 -0
  117. package/features/dynamic.feature +18 -7
  118. package/features/errors.feature +19 -5
  119. package/features/etag.feature +103 -0
  120. package/features/identity.bans.feature +137 -0
  121. package/features/identity.basic.feature +137 -14
  122. package/features/identity.feature +7 -2
  123. package/features/identity.federation.feature +61 -8
  124. package/features/identity.roles.feature +220 -4
  125. package/features/identity.tokens.feature +114 -4
  126. package/features/io.feature +205 -0
  127. package/features/octets.entries.feature +11 -1
  128. package/features/octets.feature +60 -64
  129. package/features/octets.meta.feature +7 -3
  130. package/features/octets.workflows.feature +14 -0
  131. package/features/probes.feature +14 -0
  132. package/features/{queries.feature → query.feature} +50 -3
  133. package/features/require.feature +67 -0
  134. package/features/response.feature +12 -3
  135. package/features/routes.feature +25 -12
  136. package/features/steps/Database.ts +17 -10
  137. package/features/steps/Gateway.ts +24 -4
  138. package/features/steps/IdP.ts +28 -23
  139. package/features/steps/components/echo/manifest.toa.yaml +5 -0
  140. package/features/steps/components/echo/operations/identity.js +7 -0
  141. package/features/steps/components/greeter/manifest.toa.yaml +1 -0
  142. package/features/steps/components/octets.tester/manifest.toa.yaml +1 -0
  143. package/features/steps/components/pots/manifest.toa.yaml +12 -3
  144. package/features/steps/components/sequences/manifest.toa.yaml +1 -0
  145. package/features/steps/components/users.properties/manifest.toa.yaml +2 -1
  146. package/features/streams.feature +1 -0
  147. package/features/timing.feature +69 -0
  148. package/features/vary.feature +105 -3
  149. package/package.json +12 -14
  150. package/readme.md +19 -13
  151. package/schemas/annotation.cos.yaml +2 -1
  152. package/schemas/io/input.cos.yaml +3 -0
  153. package/schemas/io/message.cos.yaml +5 -0
  154. package/schemas/io/output.cos.yaml +5 -0
  155. package/schemas/querystring.cos.yaml +1 -0
  156. package/source/Annotation.ts +3 -2
  157. package/source/Context.ts +6 -4
  158. package/source/Directive.test.ts +7 -7
  159. package/source/Directive.ts +19 -46
  160. package/source/Endpoint.ts +55 -6
  161. package/source/Factory.ts +17 -9
  162. package/source/Gateway.ts +38 -53
  163. package/source/HTTP/Context.ts +89 -0
  164. package/source/HTTP/Server.ts +99 -121
  165. package/source/HTTP/Timing.ts +40 -0
  166. package/source/HTTP/exceptions.ts +7 -1
  167. package/source/HTTP/index.ts +1 -0
  168. package/source/HTTP/messages.test.ts +27 -8
  169. package/source/HTTP/messages.ts +32 -48
  170. package/source/Mapping.ts +12 -8
  171. package/source/Query.test.ts +1 -1
  172. package/source/Query.ts +35 -24
  173. package/source/RTD/Context.ts +7 -10
  174. package/source/RTD/Directives.ts +28 -4
  175. package/source/RTD/Endpoint.ts +6 -4
  176. package/source/RTD/Match.ts +2 -7
  177. package/source/RTD/Method.ts +7 -13
  178. package/source/RTD/Node.ts +13 -14
  179. package/source/RTD/Tree.ts +17 -16
  180. package/source/RTD/factory.ts +3 -6
  181. package/source/Tenant.ts +0 -8
  182. package/source/deployment.ts +33 -17
  183. package/source/directives/auth/Anonymous.ts +3 -2
  184. package/source/directives/auth/Authorization.ts +34 -21
  185. package/source/directives/auth/Delegate.ts +35 -0
  186. package/source/directives/auth/Incept.ts +13 -7
  187. package/source/directives/auth/Role.test.ts +53 -6
  188. package/source/directives/auth/Role.ts +27 -17
  189. package/source/directives/auth/Scheme.ts +2 -2
  190. package/source/directives/auth/types.ts +1 -1
  191. package/source/directives/cache/Cache.ts +5 -5
  192. package/source/directives/cache/Control.ts +48 -22
  193. package/source/directives/cache/types.ts +1 -1
  194. package/source/directives/cors/CORS.ts +18 -10
  195. package/source/directives/dev/Development.ts +4 -4
  196. package/source/directives/index.ts +6 -4
  197. package/source/directives/io/Directive.ts +11 -0
  198. package/source/directives/io/IO.ts +43 -0
  199. package/source/directives/io/Input.ts +50 -0
  200. package/source/directives/io/Message.ts +1 -0
  201. package/source/directives/io/Output.ts +69 -0
  202. package/source/directives/io/index.ts +3 -0
  203. package/source/directives/io/schemas.ts +12 -0
  204. package/source/directives/octets/Context.ts +5 -4
  205. package/source/directives/octets/Delete.ts +23 -11
  206. package/source/directives/octets/Directive.ts +10 -0
  207. package/source/directives/octets/Fetch.ts +33 -17
  208. package/source/directives/octets/List.ts +18 -8
  209. package/source/directives/octets/Octets.ts +9 -9
  210. package/source/directives/octets/Store.ts +29 -19
  211. package/source/directives/octets/Workflow.ts +12 -5
  212. package/source/directives/octets/types.ts +0 -7
  213. package/source/directives/octets/workflows/Workflow.ts +2 -2
  214. package/source/directives/require/Directive.ts +5 -0
  215. package/source/directives/require/Headers.ts +20 -0
  216. package/source/directives/require/Require.ts +28 -0
  217. package/source/directives/require/index.ts +3 -0
  218. package/source/directives/vary/Directive.ts +2 -1
  219. package/source/directives/vary/Embed.ts +14 -8
  220. package/source/directives/vary/Vary.ts +8 -6
  221. package/source/directives/vary/embeddings/Authority.ts +8 -0
  222. package/source/directives/vary/embeddings/Embedding.ts +2 -1
  223. package/source/directives/vary/embeddings/Header.ts +9 -7
  224. package/source/directives/vary/embeddings/Language.ts +2 -2
  225. package/source/directives/vary/embeddings/Parameter.ts +14 -0
  226. package/source/directives/vary/embeddings/index.ts +6 -4
  227. package/source/exceptions.ts +22 -11
  228. package/source/io.ts +2 -2
  229. package/source/root.ts +5 -0
  230. package/source/schemas.ts +1 -1
  231. package/transpiled/Annotation.d.ts +3 -2
  232. package/transpiled/Context.d.ts +6 -4
  233. package/transpiled/Directive.d.ts +8 -21
  234. package/transpiled/Directive.js +11 -14
  235. package/transpiled/Directive.js.map +1 -1
  236. package/transpiled/Endpoint.d.ts +7 -5
  237. package/transpiled/Endpoint.js +60 -2
  238. package/transpiled/Endpoint.js.map +1 -1
  239. package/transpiled/Factory.js +11 -4
  240. package/transpiled/Factory.js.map +1 -1
  241. package/transpiled/Gateway.d.ts +4 -8
  242. package/transpiled/Gateway.js +25 -35
  243. package/transpiled/Gateway.js.map +1 -1
  244. package/transpiled/HTTP/Context.d.ts +31 -0
  245. package/transpiled/HTTP/Context.js +60 -0
  246. package/transpiled/HTTP/Context.js.map +1 -0
  247. package/transpiled/HTTP/Server.d.ts +21 -9
  248. package/transpiled/HTTP/Server.js +98 -100
  249. package/transpiled/HTTP/Server.js.map +1 -1
  250. package/transpiled/HTTP/Timing.d.ts +10 -0
  251. package/transpiled/HTTP/Timing.js +29 -0
  252. package/transpiled/HTTP/Timing.js.map +1 -0
  253. package/transpiled/HTTP/exceptions.d.ts +4 -1
  254. package/transpiled/HTTP/exceptions.js +7 -1
  255. package/transpiled/HTTP/exceptions.js.map +1 -1
  256. package/transpiled/HTTP/index.d.ts +1 -0
  257. package/transpiled/HTTP/index.js +1 -0
  258. package/transpiled/HTTP/index.js.map +1 -1
  259. package/transpiled/HTTP/messages.d.ts +7 -21
  260. package/transpiled/HTTP/messages.js +24 -26
  261. package/transpiled/HTTP/messages.js.map +1 -1
  262. package/transpiled/Mapping.js +11 -8
  263. package/transpiled/Mapping.js.map +1 -1
  264. package/transpiled/Query.d.ts +1 -0
  265. package/transpiled/Query.js +21 -20
  266. package/transpiled/Query.js.map +1 -1
  267. package/transpiled/RTD/Context.d.ts +7 -6
  268. package/transpiled/RTD/Directives.d.ts +19 -4
  269. package/transpiled/RTD/Endpoint.d.ts +6 -4
  270. package/transpiled/RTD/Match.d.ts +2 -4
  271. package/transpiled/RTD/Method.d.ts +7 -7
  272. package/transpiled/RTD/Method.js.map +1 -1
  273. package/transpiled/RTD/Node.d.ts +4 -6
  274. package/transpiled/RTD/Node.js +2 -1
  275. package/transpiled/RTD/Node.js.map +1 -1
  276. package/transpiled/RTD/Tree.d.ts +6 -6
  277. package/transpiled/RTD/Tree.js +4 -1
  278. package/transpiled/RTD/Tree.js.map +1 -1
  279. package/transpiled/RTD/factory.d.ts +2 -4
  280. package/transpiled/RTD/factory.js +1 -1
  281. package/transpiled/RTD/factory.js.map +1 -1
  282. package/transpiled/Tenant.d.ts +0 -1
  283. package/transpiled/Tenant.js +0 -6
  284. package/transpiled/Tenant.js.map +1 -1
  285. package/transpiled/deployment.d.ts +1 -1
  286. package/transpiled/deployment.js +28 -15
  287. package/transpiled/deployment.js.map +1 -1
  288. package/transpiled/directives/auth/Anonymous.js +3 -4
  289. package/transpiled/directives/auth/Anonymous.js.map +1 -1
  290. package/transpiled/directives/auth/Authorization.d.ts +2 -3
  291. package/transpiled/directives/auth/Authorization.js +18 -11
  292. package/transpiled/directives/auth/Authorization.js.map +1 -1
  293. package/transpiled/directives/auth/Delegate.d.ts +8 -0
  294. package/transpiled/directives/auth/Delegate.js +29 -0
  295. package/transpiled/directives/auth/Delegate.js.map +1 -0
  296. package/transpiled/directives/auth/Incept.d.ts +1 -1
  297. package/transpiled/directives/auth/Incept.js +13 -7
  298. package/transpiled/directives/auth/Incept.js.map +1 -1
  299. package/transpiled/directives/auth/Role.d.ts +4 -1
  300. package/transpiled/directives/auth/Role.js +25 -17
  301. package/transpiled/directives/auth/Role.js.map +1 -1
  302. package/transpiled/directives/auth/Scheme.js +2 -2
  303. package/transpiled/directives/auth/Scheme.js.map +1 -1
  304. package/transpiled/directives/cache/Cache.d.ts +3 -3
  305. package/transpiled/directives/cache/Cache.js +3 -3
  306. package/transpiled/directives/cache/Cache.js.map +1 -1
  307. package/transpiled/directives/cache/Control.d.ts +5 -4
  308. package/transpiled/directives/cache/Control.js +32 -15
  309. package/transpiled/directives/cache/Control.js.map +1 -1
  310. package/transpiled/directives/cache/types.d.ts +1 -1
  311. package/transpiled/directives/cors/CORS.d.ts +2 -3
  312. package/transpiled/directives/cors/CORS.js +17 -10
  313. package/transpiled/directives/cors/CORS.js.map +1 -1
  314. package/transpiled/directives/dev/Development.d.ts +3 -3
  315. package/transpiled/directives/dev/Development.js +1 -1
  316. package/transpiled/directives/dev/Development.js.map +1 -1
  317. package/transpiled/directives/index.d.ts +2 -2
  318. package/transpiled/directives/index.js +5 -3
  319. package/transpiled/directives/index.js.map +1 -1
  320. package/transpiled/directives/io/Directive.d.ts +8 -0
  321. package/transpiled/directives/io/Directive.js +3 -0
  322. package/transpiled/directives/io/Directive.js.map +1 -0
  323. package/transpiled/directives/io/IO.d.ts +9 -0
  324. package/transpiled/directives/io/IO.js +33 -0
  325. package/transpiled/directives/io/IO.js.map +1 -0
  326. package/transpiled/directives/io/Input.d.ts +11 -0
  327. package/transpiled/directives/{octets/Permute.js → io/Input.js} +33 -21
  328. package/transpiled/directives/io/Input.js.map +1 -0
  329. package/transpiled/directives/io/Message.d.ts +1 -0
  330. package/transpiled/directives/io/Message.js +3 -0
  331. package/transpiled/directives/io/Message.js.map +1 -0
  332. package/transpiled/directives/io/Output.d.ts +13 -0
  333. package/transpiled/directives/io/Output.js +76 -0
  334. package/transpiled/directives/io/Output.js.map +1 -0
  335. package/transpiled/directives/io/index.d.ts +2 -0
  336. package/transpiled/directives/io/index.js +6 -0
  337. package/transpiled/directives/io/index.js.map +1 -0
  338. package/transpiled/directives/io/schemas.d.ts +7 -0
  339. package/transpiled/directives/io/schemas.js +14 -0
  340. package/transpiled/directives/io/schemas.js.map +1 -0
  341. package/transpiled/directives/octets/Context.d.ts +4 -4
  342. package/transpiled/directives/octets/Context.js +4 -2
  343. package/transpiled/directives/octets/Context.js.map +1 -1
  344. package/transpiled/directives/octets/Delete.d.ts +4 -3
  345. package/transpiled/directives/octets/Delete.js +22 -10
  346. package/transpiled/directives/octets/Delete.js.map +1 -1
  347. package/transpiled/directives/octets/Directive.d.ts +8 -0
  348. package/transpiled/directives/octets/Directive.js +8 -0
  349. package/transpiled/directives/octets/Directive.js.map +1 -0
  350. package/transpiled/directives/octets/Fetch.d.ts +4 -3
  351. package/transpiled/directives/octets/Fetch.js +31 -15
  352. package/transpiled/directives/octets/Fetch.js.map +1 -1
  353. package/transpiled/directives/octets/List.d.ts +4 -3
  354. package/transpiled/directives/octets/List.js +16 -7
  355. package/transpiled/directives/octets/List.js.map +1 -1
  356. package/transpiled/directives/octets/Octets.d.ts +4 -4
  357. package/transpiled/directives/octets/Octets.js +5 -5
  358. package/transpiled/directives/octets/Octets.js.map +1 -1
  359. package/transpiled/directives/octets/Store.d.ts +4 -3
  360. package/transpiled/directives/octets/Store.js +20 -13
  361. package/transpiled/directives/octets/Store.js.map +1 -1
  362. package/transpiled/directives/octets/Workflow.d.ts +4 -3
  363. package/transpiled/directives/octets/Workflow.js +11 -4
  364. package/transpiled/directives/octets/Workflow.js.map +1 -1
  365. package/transpiled/directives/octets/types.d.ts +0 -5
  366. package/transpiled/directives/octets/workflows/Workflow.d.ts +1 -1
  367. package/transpiled/directives/octets/workflows/Workflow.js +2 -2
  368. package/transpiled/directives/octets/workflows/Workflow.js.map +1 -1
  369. package/transpiled/directives/require/Directive.d.ts +4 -0
  370. package/transpiled/directives/require/Directive.js +3 -0
  371. package/transpiled/directives/require/Directive.js.map +1 -0
  372. package/transpiled/directives/require/Headers.d.ts +7 -0
  373. package/transpiled/directives/require/Headers.js +19 -0
  374. package/transpiled/directives/require/Headers.js.map +1 -0
  375. package/transpiled/directives/require/Require.d.ts +9 -0
  376. package/transpiled/directives/require/Require.js +27 -0
  377. package/transpiled/directives/require/Require.js.map +1 -0
  378. package/transpiled/directives/require/index.d.ts +2 -0
  379. package/transpiled/directives/require/index.js +6 -0
  380. package/transpiled/directives/require/index.js.map +1 -0
  381. package/transpiled/directives/vary/Directive.d.ts +2 -1
  382. package/transpiled/directives/vary/Embed.d.ts +2 -1
  383. package/transpiled/directives/vary/Embed.js +8 -6
  384. package/transpiled/directives/vary/Embed.js.map +1 -1
  385. package/transpiled/directives/vary/Vary.d.ts +3 -3
  386. package/transpiled/directives/vary/Vary.js +4 -4
  387. package/transpiled/directives/vary/Vary.js.map +1 -1
  388. package/transpiled/directives/vary/embeddings/Authority.d.ts +5 -0
  389. package/transpiled/directives/vary/embeddings/Authority.js +10 -0
  390. package/transpiled/directives/vary/embeddings/Authority.js.map +1 -0
  391. package/transpiled/directives/vary/embeddings/Embedding.d.ts +2 -1
  392. package/transpiled/directives/vary/embeddings/Header.js +9 -7
  393. package/transpiled/directives/vary/embeddings/Header.js.map +1 -1
  394. package/transpiled/directives/vary/embeddings/Language.js +2 -2
  395. package/transpiled/directives/vary/embeddings/Language.js.map +1 -1
  396. package/transpiled/directives/vary/embeddings/Parameter.d.ts +7 -0
  397. package/transpiled/directives/vary/embeddings/Parameter.js +14 -0
  398. package/transpiled/directives/vary/embeddings/Parameter.js.map +1 -0
  399. package/transpiled/directives/vary/embeddings/index.d.ts +2 -2
  400. package/transpiled/directives/vary/embeddings/index.js +8 -4
  401. package/transpiled/directives/vary/embeddings/index.js.map +1 -1
  402. package/transpiled/exceptions.d.ts +3 -2
  403. package/transpiled/exceptions.js +13 -7
  404. package/transpiled/exceptions.js.map +1 -1
  405. package/transpiled/io.d.ts +2 -2
  406. package/transpiled/root.js +5 -0
  407. package/transpiled/root.js.map +1 -1
  408. package/transpiled/schemas.d.ts +1 -1
  409. package/transpiled/schemas.js +2 -2
  410. package/transpiled/schemas.js.map +1 -1
  411. package/transpiled/tsconfig.tsbuildinfo +1 -1
  412. package/components/identity.basic/operations/create.d.ts +0 -10
  413. package/components/identity.basic/operations/create.js +0 -10
  414. package/components/identity.basic/operations/create.js.map +0 -1
  415. package/components/identity.basic/source/create.ts +0 -18
  416. package/components/identity.federation/operations/create.d.ts +0 -10
  417. package/components/identity.federation/operations/create.js.map +0 -1
  418. package/components/identity.federation/operations/schemas.d.ts +0 -59
  419. package/components/identity.federation/operations/schemas.js +0 -9
  420. package/components/identity.federation/operations/schemas.js.map +0 -1
  421. package/components/identity.federation/operations/types.js.map +0 -1
  422. package/components/identity.federation/source/schemas.ts +0 -61
  423. package/components/octets.storage/operations/permute.js +0 -7
  424. package/source/HTTP/Server.fixtures.ts +0 -40
  425. package/source/HTTP/Server.test.ts +0 -126
  426. package/source/directives/octets/Permute.ts +0 -37
  427. package/transpiled/HTTP/Server.fixtures.d.ts +0 -10
  428. package/transpiled/HTTP/Server.fixtures.js +0 -31
  429. package/transpiled/HTTP/Server.fixtures.js.map +0 -1
  430. package/transpiled/directives/octets/Permute.d.ts +0 -10
  431. package/transpiled/directives/octets/Permute.js.map +0 -1
package/source/Factory.ts CHANGED
@@ -1,14 +1,17 @@
1
+ import assert from 'node:assert'
2
+ import { decode } from '@toa.io/generic'
1
3
  import { Tenant } from './Tenant'
2
4
  import { Gateway } from './Gateway'
3
5
  import { Remotes } from './Remotes'
4
6
  import { Tree, syntax } from './RTD'
5
- import { Server } from './HTTP'
6
- import { type Endpoint, EndpointsFactory } from './Endpoint'
7
+ import { EndpointsFactory } from './Endpoint'
7
8
  import { families, interceptors } from './directives'
8
- import { type Directives, DirectivesFactory } from './Directive'
9
+ import { DirectivesFactory } from './Directive'
9
10
  import { Composition } from './Composition'
10
11
  import * as root from './root'
11
12
  import { Interception } from './Interception'
13
+ import * as http from './HTTP'
14
+ import type { Broadcast } from './Gateway'
12
15
  import type { Connector, Locator, extensions } from '@toa.io/core'
13
16
 
14
17
  export class Factory implements extensions.Factory {
@@ -19,27 +22,32 @@ export class Factory implements extensions.Factory {
19
22
  }
20
23
 
21
24
  public tenant (locator: Locator, node: syntax.Node): Connector {
22
- const broadcast = this.boot.bindings.broadcast(CHANNEL, locator.id)
25
+ const broadcast: Broadcast = this.boot.bindings.broadcast(CHANNEL, locator.id)
23
26
 
24
27
  return new Tenant(broadcast, locator, node)
25
28
  }
26
29
 
27
30
  public service (): Connector | null {
28
- const debug = process.env.TOA_EXPOSITION_DEBUG === '1'
29
- const broadcast = this.boot.bindings.broadcast(CHANNEL)
30
- const server = Server.create({ methods: syntax.verbs, debug })
31
+ assert.ok(process.env.TOA_EXPOSITION_PROPERTIES,
32
+ 'TOA_EXPOSITION_PROPERTIES is undefined')
33
+
34
+ const options = decode<http.Options>(process.env.TOA_EXPOSITION_PROPERTIES)
35
+ const broadcast: Broadcast = this.boot.bindings.broadcast(CHANNEL)
36
+ const server = http.Server.create({ ...options, methods: syntax.verbs })
31
37
  const remotes = new Remotes(this.boot)
32
38
  const node = root.resolve()
33
39
  const methods = new EndpointsFactory(remotes)
34
40
  const directives = new DirectivesFactory(families, remotes)
35
41
  const interception = new Interception(interceptors)
36
- const tree = new Tree<Endpoint, Directives>(node, methods, directives)
42
+ const tree = new Tree(node, methods, directives)
37
43
 
38
44
  const composition = new Composition(this.boot)
39
- const gateway = new Gateway(broadcast, server, tree, interception)
45
+ const gateway = new Gateway(broadcast, tree, interception)
40
46
 
41
47
  gateway.depends(remotes)
42
48
  gateway.depends(composition)
49
+
50
+ server.attach(gateway.process.bind(gateway))
43
51
  server.depends(gateway)
44
52
 
45
53
  return server
package/source/Gateway.ts CHANGED
@@ -1,95 +1,80 @@
1
1
  import { type bindings, Connector } from '@toa.io/core'
2
2
  import * as http from './HTTP'
3
3
  import { rethrow } from './exceptions'
4
- import type { Interceptor } from './Interception'
5
- import type { Maybe } from '@toa.io/types'
4
+ import type { Interception } from './Interception'
6
5
  import type { Method, Parameter, Tree } from './RTD'
7
6
  import type { Label } from './discovery'
8
7
  import type { Branch } from './Branch'
9
- import type { Endpoint } from './Endpoint'
10
- import type { Directives } from './Directive'
11
8
 
12
9
  export class Gateway extends Connector {
13
10
  private readonly broadcast: Broadcast
14
- private readonly tree: Tree<Endpoint, Directives>
15
- private readonly interceptor: Interceptor
16
- private readonly server: Connector
11
+ private readonly tree: Tree
12
+ private readonly interceptor: Interception
17
13
 
18
- // eslint-disable-next-line max-params, max-len
19
- public constructor (broadcast: Broadcast, server: http.Server, tree: Tree<Endpoint, Directives>, interception: Interceptor) {
14
+ public constructor (broadcast: Broadcast, tree: Tree, interception: Interception) {
20
15
  super()
21
16
 
22
17
  this.broadcast = broadcast
23
18
  this.tree = tree
24
19
  this.interceptor = interception
25
- this.server = server
26
20
 
27
21
  this.depends(broadcast)
28
- // this.depends(server)
29
-
30
- server.attach(this.process.bind(this))
31
- }
32
-
33
- protected override async open (): Promise<void> {
34
- await this.discover()
35
-
36
- console.info('Gateway has started and is awaiting resource branches.')
37
22
  }
38
23
 
39
- protected override dispose (): void {
40
- console.info('Gateway is closed.')
41
- }
42
-
43
- private async process (request: http.IncomingMessage): Promise<http.OutgoingMessage> {
44
- const interception = await this.interceptor.intercept(request)
24
+ public async process (context: http.Context): Promise<http.OutgoingMessage> {
25
+ const interception = await context.timing.capture('intercept',
26
+ this.interceptor.intercept(context))
45
27
 
46
28
  if (interception !== null)
47
29
  return interception
48
30
 
49
- const match = this.tree.match(request.path)
31
+ const match = this.tree.match(context.url.pathname)
50
32
 
51
33
  if (match === null)
52
- throw new http.NotFound()
34
+ throw new http.NotFound('Route not found')
53
35
 
54
36
  const { node, parameters } = match
55
37
 
56
- if (!(request.method in node.methods))
38
+ if (!(context.request.method in node.methods))
57
39
  throw new http.MethodNotAllowed()
58
40
 
59
- const method = node.methods[request.method]
60
- const interruption = await method.directives.preflight(request, parameters)
61
- const response = interruption ?? await this.call(method, request, parameters)
41
+ const method = node.methods[context.request.method]
62
42
 
63
- await method.directives.settle(request, response)
43
+ const interruption = await context.timing.capture('preflight',
44
+ method.directives.preflight(context, parameters)).catch(rethrow)
45
+
46
+ const response = interruption ??
47
+ await context.timing.capture('call', this.call(method, context, parameters))
48
+
49
+ await context.timing.capture('settle',
50
+ method.directives.settle(context, response)).catch(rethrow)
64
51
 
65
52
  return response
66
53
  }
67
54
 
68
- private async call
69
- (method: Method<Endpoint, Directives>, request: http.IncomingMessage, parameters: Parameter[]):
70
- Promise<http.OutgoingMessage> {
71
- if (request.path[request.path.length - 1] !== '/')
72
- throw new http.NotFound('Trailing slash is required.')
73
-
74
- if (request.encoder === null)
75
- throw new http.NotAcceptable()
55
+ protected override async open (): Promise<void> {
56
+ await this.discover()
76
57
 
77
- if (method.endpoint === null)
78
- throw new http.MethodNotAllowed()
58
+ console.info('Gateway has started and is awaiting resource branches')
59
+ }
79
60
 
80
- const body = await request.parse()
61
+ protected override dispose (): void {
62
+ console.info('Gateway is closed')
63
+ }
81
64
 
82
- if ('embed' in request && typeof body === 'object' && body !== null)
83
- Object.assign(body, request.embed)
65
+ private async call (method: Method, context: http.Context, parameters: Parameter[]): Promise<http.OutgoingMessage> {
66
+ if (context.url.pathname[context.url.pathname.length - 1] !== '/')
67
+ throw new http.NotFound('Trailing slash is required')
84
68
 
85
- const reply = await method.endpoint
86
- .call(body, request.query, parameters)
87
- .catch(rethrow) as Maybe<unknown>
69
+ if (context.encoder === null)
70
+ throw new http.NotAcceptable()
88
71
 
89
- if (reply instanceof Error)
90
- throw new http.Conflict(reply)
72
+ if (method.endpoint === null)
73
+ throw new http.MethodNotAllowed()
91
74
 
92
- return { body: reply }
75
+ return await method.endpoint
76
+ .call(context, parameters)
77
+ .catch(rethrow) as http.OutgoingMessage
93
78
  }
94
79
 
95
80
  private async discover (): Promise<void> {
@@ -102,11 +87,11 @@ export class Gateway extends Connector {
102
87
  this.tree.merge(branch.node, branch)
103
88
 
104
89
  console.info('Resource branch of ' +
105
- `'${branch.namespace}.${branch.component}' has been merged.`)
90
+ `'${branch.namespace}.${branch.component}' has been merged`)
106
91
  } catch (exception) {
107
92
  console.error(exception)
108
93
  }
109
94
  }
110
95
  }
111
96
 
112
- type Broadcast = bindings.Broadcast<Label>
97
+ export type Broadcast = bindings.Broadcast<Label>
@@ -0,0 +1,89 @@
1
+ import Negotiator from 'negotiator'
2
+ import { Timing } from './Timing'
3
+ import { type Format, formats, types } from './formats'
4
+ import { read } from './messages'
5
+ import type { OutgoingMessage } from './messages'
6
+ import type * as http from 'node:http'
7
+
8
+ export class Context {
9
+ public readonly authority: string
10
+ public readonly request: IncomingMessage
11
+ public readonly url: URL
12
+ public readonly subtype: string | null = null
13
+ public readonly encoder: Format | null = null
14
+ public readonly timing: Timing
15
+ public readonly debug: boolean
16
+
17
+ public readonly pipelines: Pipelines = {
18
+ body: [],
19
+ response: []
20
+ }
21
+
22
+ public constructor (authority: string, request: IncomingMessage, properties: Properties) {
23
+ this.authority = authority
24
+ this.request = request
25
+
26
+ this.url = new URL(request.url, `https://${request.headers.host}`)
27
+ this.timing = new Timing(properties.trace)
28
+ this.debug = properties.debug
29
+
30
+ if (this.debug)
31
+ this.log(request)
32
+
33
+ if (this.request.headers.accept !== undefined) {
34
+ const match = SUBTYPE.exec(this.request.headers.accept)
35
+
36
+ if (match !== null) {
37
+ const {
38
+ type,
39
+ subtype,
40
+ suffix
41
+ } = match.groups!
42
+
43
+ this.request.headers.accept = `${type}/${suffix}`
44
+ this.subtype = subtype
45
+ }
46
+ }
47
+
48
+ const negotiator = new Negotiator(this.request)
49
+ const mediaType = negotiator.mediaType(types)
50
+
51
+ if (mediaType !== undefined)
52
+ this.encoder = formats[mediaType]
53
+ }
54
+
55
+ public async body<T> (): Promise<T> {
56
+ const value = await read(this)
57
+
58
+ return this.pipelines.body.length === 0
59
+ ? value
60
+ : this.pipelines.body.reduce((value, transform) => transform(value), value)
61
+ }
62
+
63
+ private log (request: IncomingMessage): void {
64
+ const message = `${request.method} ${request.url}`
65
+ const { authorization, ...headers } = request.headers
66
+
67
+ if (authorization !== undefined)
68
+ headers.authorization = authorization.slice(0, authorization.indexOf(' '))
69
+
70
+ console.debug(message, headers)
71
+ }
72
+ }
73
+
74
+ export interface IncomingMessage extends http.IncomingMessage {
75
+ url: string
76
+ method: string
77
+ }
78
+
79
+ interface Pipelines {
80
+ body: Array<(input: unknown) => unknown>
81
+ response: Array<(output: OutgoingMessage) => void>
82
+ }
83
+
84
+ interface Properties {
85
+ debug: boolean
86
+ trace: boolean
87
+ }
88
+
89
+ const SUBTYPE = /^(?<type>\w{1,32})\/(vnd\.toa\.(?<subtype>\S{1,32})\+)(?<suffix>\S{1,32})$/
@@ -1,193 +1,171 @@
1
1
  import fs from 'node:fs'
2
2
  import os from 'node:os'
3
- import express from 'express'
3
+ import * as http from 'node:http'
4
+ import { once } from 'node:events'
5
+ import { setTimeout } from 'node:timers/promises'
4
6
  import { Connector } from '@toa.io/core'
5
- import { promex } from '@toa.io/generic'
6
- import Negotiator from 'negotiator'
7
- import { read, write, type IncomingMessage, type OutgoingMessage } from './messages'
7
+ import { type OutgoingMessage, write } from './messages'
8
8
  import { ClientError, Exception } from './exceptions'
9
- import { formats, types } from './formats'
10
- import type * as http from 'node:http'
11
- import type { Express, Request, Response, NextFunction } from 'express'
9
+ import { Context } from './Context'
10
+ import type { IncomingMessage } from './Context'
12
11
 
13
12
  export class Server extends Connector {
14
- private server?: http.Server
15
- private readonly app: Express
16
- private readonly debug: boolean
17
- private readonly requestedPort: number
18
-
19
- private constructor (app: Express, debug: boolean, port: number) {
13
+ private readonly server: http.Server = http.createServer()
14
+ private readonly properties: Properties
15
+ private readonly authorities: Record<string, string>
16
+ private process?: Processing
17
+ private ready: boolean = false
18
+ private startedAt: number = 0
19
+
20
+ private constructor (properties: Properties) {
20
21
  super()
21
22
 
22
- this.app = app
23
- this.debug = debug
24
- this.requestedPort = port
25
- }
26
-
27
- public get port (): number {
28
- if (this.server === undefined) return this.requestedPort
29
-
30
- const address = this.server.address()
23
+ this.properties = properties
24
+ this.authorities = Object.fromEntries(Object.entries(properties.authorities).map(([key, value]) => [value, key]))
31
25
 
32
- if (address === null || typeof address === 'string')
33
- throw new Error('Server is not listening on a port.')
34
-
35
- return address.port
26
+ this.server.on('request', (req, res) => this.listener(req, res))
36
27
  }
37
28
 
38
- public static create (options?: Partial<Properties>): Server {
39
- const properties = options === undefined
40
- ? DEFAULTS
41
- : { ...DEFAULTS, ...options }
42
-
43
- const app = express()
29
+ public static create (options: Options): Server {
30
+ const properties: Properties = Object.assign({}, DEFAULTS, options)
44
31
 
45
- app.disable('x-powered-by')
46
- app.use(supportedMethods(properties.methods))
47
-
48
- return new Server(app, properties.debug, properties.port)
32
+ return new Server(properties)
49
33
  }
50
34
 
51
35
  public attach (process: Processing): void {
52
- this.app.use((request: Request, response: Response) => {
53
- const message = this.extend(request)
54
-
55
- process(message)
56
- .then(this.success(message, response))
57
- .catch(this.fail(message, response))
58
- })
36
+ this.process = process
59
37
  }
60
38
 
61
39
  protected override async open (): Promise<void> {
62
- const listening = promex()
40
+ this.startedAt = Date.now()
41
+ this.server.listen(this.properties.port)
63
42
 
64
- this.server = this.app.listen(this.requestedPort, listening.callback)
43
+ await once(this.server, 'listening')
65
44
 
66
- await listening
45
+ console.info('HTTP Server is listening')
67
46
 
68
- console.info('HTTP Server is listening.')
47
+ await setTimeout(this.properties.delay)
48
+
49
+ this.ready = true
50
+
51
+ console.info('Ready')
69
52
  }
70
53
 
71
54
  protected override async close (): Promise<void> {
72
- const stopped = promex()
55
+ this.server.close()
56
+ this.ready = false
73
57
 
74
- this.server?.close(stopped.callback)
58
+ console.info('HTTP Server stopped accepting new connections')
75
59
 
76
- await stopped
60
+ await once(this.server, 'close')
77
61
 
78
- this.server = undefined
79
-
80
- console.info('HTTP Server has been stopped.')
62
+ console.info('HTTP Server has been stopped')
81
63
  }
82
64
 
83
- private extend (request: Request): IncomingMessage {
84
- const message = request as IncomingMessage
65
+ private listener (request: http.IncomingMessage, response: http.ServerResponse): void {
66
+ if (request.method === undefined || !this.properties.methods.has(request.method)) {
67
+ response.writeHead(501).end()
85
68
 
86
- negotiate(request, message)
69
+ return
70
+ }
87
71
 
88
- message.pipelines = { body: [], response: [] }
72
+ if (request.url === '/.ready') {
73
+ if (this.ready)
74
+ response.writeHead(200, { 'cache-control': 'no-store' }).end()
75
+ else {
76
+ const remaining = (Math.ceil((Date.now() - this.startedAt) / 1000)).toString()
89
77
 
90
- message.parse = async <T> (): Promise<T> => {
91
- const value = await read(request)
78
+ response.writeHead(503, { 'retry-after': remaining }).end()
79
+ }
92
80
 
93
- if (message.pipelines.body.length === 0)
94
- return value
81
+ return
82
+ }
83
+
84
+ if (request.headers.host === undefined || !(request.headers.host in this.authorities)) {
85
+ response.writeHead(404).end('Unknown authority')
95
86
 
96
- return message.pipelines.body.reduce((value, transform) => transform(value), value)
87
+ return
97
88
  }
98
89
 
99
- return message
90
+ const authority = this.authorities[request.headers.host]
91
+ const context = new Context(authority, request as IncomingMessage, this.properties)
92
+
93
+ this.process!(context)
94
+ .then(this.success(context, response))
95
+ .catch(this.fail(context, response))
100
96
  }
101
97
 
102
- private success (request: IncomingMessage, response: Response) {
98
+ private success (context: Context, response: http.ServerResponse) {
103
99
  return (message: OutgoingMessage) => {
104
100
  let status = message.status
105
101
 
106
102
  if (status === undefined)
107
- if (message.body === null) status = 404
108
- else if (request.method === 'POST') status = 201
109
- else if (message.body === undefined) status = 204
110
- else status = 200
111
-
112
- response.status(status)
113
- write(request, response, message)
103
+ if (message.body === null)
104
+ status = 404
105
+ else if (context.request.method === 'POST')
106
+ status = 201
107
+ else if (message.body === undefined)
108
+ status = 204
109
+ else
110
+ status = 200
111
+
112
+ response.statusCode = message.status = status
113
+ write(context, response, message)
114
114
  }
115
115
  }
116
116
 
117
- private fail (request: IncomingMessage, response: Response) {
117
+ private fail (context: Context, response: http.ServerResponse) {
118
118
  return async (exception: Error) => {
119
- if (!request.complete)
120
- await adam(request)
121
-
122
- const status = exception instanceof Exception
123
- ? exception.status
124
- : 500
119
+ if (!context.request.complete)
120
+ await adam(context.request)
125
121
 
126
- response.status(status)
122
+ response.statusCode = exception instanceof Exception ? exception.status : 500
127
123
 
128
- const message: OutgoingMessage = {}
129
- const verbose = exception instanceof ClientError || this.debug
124
+ const message: OutgoingMessage = { status: response.statusCode }
125
+ const verbose = exception instanceof ClientError || this.properties.debug
130
126
 
131
127
  if (verbose)
132
- message.body = exception instanceof Exception
133
- ? exception.body
134
- : (exception.stack ?? exception.message)
128
+ message.body =
129
+ exception instanceof Exception
130
+ ? exception.body
131
+ : exception.stack ?? exception.message
135
132
 
136
- write(request, response, message)
133
+ write(context, response, message)
137
134
  }
138
135
  }
139
136
  }
140
137
 
141
- function supportedMethods (methods: Set<string>) {
142
- return (req: Request, res: Response, next: NextFunction): void => {
143
- if (methods.has(req.method)) next()
144
- else res.sendStatus(501)
145
- }
146
- }
147
-
148
- function negotiate (request: Request, message: IncomingMessage): void {
149
- if (request.headers.accept !== undefined) {
150
- const match = SUBTYPE.exec(request.headers.accept)
151
-
152
- if (match !== null) {
153
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
154
- const { type, subtype, suffix } = match.groups!
155
-
156
- request.headers.accept = `${type}/${suffix}`
157
- message.subtype = subtype
158
- }
159
- }
160
-
161
- const negotiator = new Negotiator(request)
162
- const mediaType = negotiator.mediaType(types)
163
-
164
- message.encoder = mediaType === undefined ? null : formats[mediaType]
165
- }
166
-
167
138
  // https://github.com/whatwg/fetch/issues/1254
168
- async function adam (request: Request): Promise<void> {
169
- const completed = promex()
139
+ async function adam (request: http.IncomingMessage): Promise<any> {
170
140
  const devnull = fs.createWriteStream(os.devNull)
171
141
 
172
- request
173
- .on('end', completed.callback)
174
- .pipe(devnull)
142
+ request.pipe(devnull)
175
143
 
176
- return await completed
144
+ return once(request, 'end')
177
145
  }
178
146
 
179
- const DEFAULTS: Properties = {
147
+ export const PORT = 8000
148
+ export const DELAY = 3 // seconds
149
+
150
+ const DEFAULTS: Omit<Properties, 'authorities'> = {
180
151
  methods: new Set<string>(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),
181
152
  debug: false,
182
- port: 8000
153
+ trace: false,
154
+ port: PORT,
155
+ delay: DELAY * 1000
183
156
  }
184
157
 
185
158
  interface Properties {
159
+ authorities: Record<string, string>
186
160
  methods: Set<string>
187
161
  debug: boolean
162
+ trace: boolean
188
163
  port: number
164
+ delay: number
189
165
  }
190
166
 
191
- export type Processing = (input: IncomingMessage) => Promise<OutgoingMessage>
167
+ export type Options = { authorities: Properties['authorities'] } & {
168
+ [K in Exclude<keyof Properties, 'authorities'>]?: Properties[K]
169
+ }
192
170
 
193
- const SUBTYPE = /^(?<type>\w{1,32})\/(vnd\.toa\.(?<subtype>\S{1,32})\+)(?<suffix>\S{1,32})$/
171
+ export type Processing = (input: Context) => Promise<OutgoingMessage>
@@ -0,0 +1,40 @@
1
+ import { performance } from 'node:perf_hooks'
2
+ import type { ServerResponse } from 'node:http'
3
+
4
+ export class Timing {
5
+ private readonly skip: boolean
6
+ private readonly start = performance.now()
7
+ private readonly breakpoints: Breakpoint[] = []
8
+
9
+ public constructor (enabled: boolean) {
10
+ this.skip = !enabled
11
+ }
12
+
13
+ public async capture<T> (id: string, promise: Promise<T>): Promise<T> {
14
+ if (this.skip)
15
+ return promise
16
+
17
+ const start = performance.now()
18
+ const result = promise instanceof Promise ? await promise : promise
19
+
20
+ this.breakpoints.push({ id, duration: performance.now() - start })
21
+
22
+ return result
23
+ }
24
+
25
+ public append (response: ServerResponse): void {
26
+ if (this.skip)
27
+ return
28
+
29
+ this.breakpoints.push({ id: 'total', duration: performance.now() - this.start })
30
+
31
+ for (const breakpoint of this.breakpoints)
32
+ response.appendHeader('server-timing',
33
+ `${breakpoint.id};dur=${breakpoint.duration.toFixed(3)}`)
34
+ }
35
+ }
36
+
37
+ interface Breakpoint {
38
+ id: string
39
+ duration: number
40
+ }
@@ -37,11 +37,17 @@ export class NotFound extends ClientError {
37
37
  }
38
38
 
39
39
  export class Conflict extends ClientError {
40
- public constructor (body: any) {
40
+ public constructor (body?: any) {
41
41
  super(409, body)
42
42
  }
43
43
  }
44
44
 
45
+ export class UnprocessableEntity extends ClientError {
46
+ public constructor (body?: any) {
47
+ super(422, body)
48
+ }
49
+ }
50
+
45
51
  export class MethodNotAllowed extends ClientError {
46
52
  public constructor () {
47
53
  super(405)
@@ -1,3 +1,4 @@
1
1
  export * from './Server'
2
2
  export * from './messages'
3
3
  export * from './exceptions'
4
+ export * from './Context'