@toa.io/extensions.exposition 1.0.0-alpha.0 → 1.0.0-alpha.10

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 (547) hide show
  1. package/components/context.toa.yaml +12 -0
  2. package/components/identity.bans/manifest.toa.yaml +2 -1
  3. package/components/identity.basic/manifest.toa.yaml +6 -2
  4. package/components/identity.basic/operations/authenticate.d.ts +9 -0
  5. package/components/identity.basic/operations/authenticate.js +24 -0
  6. package/components/identity.basic/operations/authenticate.js.map +1 -0
  7. package/components/identity.basic/operations/create.d.ts +10 -0
  8. package/components/identity.basic/operations/create.js +10 -0
  9. package/components/identity.basic/operations/create.js.map +1 -0
  10. package/components/identity.basic/operations/transit.d.ts +12 -0
  11. package/components/identity.basic/operations/transit.js +53 -0
  12. package/components/identity.basic/operations/transit.js.map +1 -0
  13. package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -0
  14. package/components/identity.basic/operations/types.d.ts +38 -0
  15. package/components/identity.basic/operations/types.js +3 -0
  16. package/components/identity.basic/operations/types.js.map +1 -0
  17. package/components/identity.basic/source/authenticate.ts +0 -1
  18. package/components/identity.federation/events/principal.js +22 -0
  19. package/components/identity.federation/manifest.toa.yaml +94 -0
  20. package/components/identity.federation/operations/authenticate.d.ts +3 -0
  21. package/components/identity.federation/operations/authenticate.js +20 -0
  22. package/components/identity.federation/operations/authenticate.js.map +1 -0
  23. package/components/identity.federation/operations/create.d.ts +10 -0
  24. package/components/identity.federation/operations/create.js +15 -0
  25. package/components/identity.federation/operations/create.js.map +1 -0
  26. package/components/identity.federation/operations/lib/assertions-as-values.d.ts +4 -0
  27. package/components/identity.federation/operations/lib/assertions-as-values.js +45 -0
  28. package/components/identity.federation/operations/lib/assertions-as-values.js.map +1 -0
  29. package/components/identity.federation/operations/lib/jwt.d.ts +20 -0
  30. package/components/identity.federation/operations/lib/jwt.js +136 -0
  31. package/components/identity.federation/operations/lib/jwt.js.map +1 -0
  32. package/components/identity.federation/operations/schemas.d.ts +59 -0
  33. package/components/identity.federation/operations/schemas.js +9 -0
  34. package/components/identity.federation/operations/schemas.js.map +1 -0
  35. package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -0
  36. package/components/identity.federation/operations/types.d.ts +51 -0
  37. package/components/identity.federation/operations/types.js +3 -0
  38. package/components/identity.federation/operations/types.js.map +1 -0
  39. package/components/identity.federation/source/authenticate.ts +28 -0
  40. package/components/identity.federation/source/create.ts +26 -0
  41. package/components/identity.federation/source/lib/assertions-as-values.ts +19 -0
  42. package/components/identity.federation/source/lib/jwt.test.ts +56 -0
  43. package/components/identity.federation/source/lib/jwt.ts +171 -0
  44. package/components/identity.federation/source/schemas.ts +61 -0
  45. package/components/identity.federation/source/types.ts +56 -0
  46. package/components/identity.federation/tsconfig.json +9 -0
  47. package/components/identity.roles/manifest.toa.yaml +17 -5
  48. package/components/identity.roles/operations/grant.d.ts +10 -0
  49. package/components/identity.roles/operations/grant.js +20 -0
  50. package/components/identity.roles/operations/grant.js.map +1 -0
  51. package/components/identity.roles/operations/lib/Entity.d.ts +5 -0
  52. package/components/identity.roles/operations/lib/Entity.js +3 -0
  53. package/components/identity.roles/operations/lib/Entity.js.map +1 -0
  54. package/components/identity.roles/operations/list.d.ts +2 -0
  55. package/components/identity.roles/operations/list.js +8 -0
  56. package/components/identity.roles/operations/list.js.map +1 -0
  57. package/components/identity.roles/operations/principal.d.ts +13 -0
  58. package/components/identity.roles/operations/principal.js +13 -0
  59. package/components/identity.roles/operations/principal.js.map +1 -0
  60. package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -0
  61. package/components/identity.roles/source/grant.ts +31 -0
  62. package/components/identity.roles/source/lib/Entity.ts +5 -0
  63. package/components/identity.roles/source/list.ts +2 -4
  64. package/components/identity.roles/source/principal.ts +10 -8
  65. package/components/identity.tokens/manifest.toa.yaml +1 -1
  66. package/components/identity.tokens/operations/authenticate.d.ts +9 -0
  67. package/components/identity.tokens/operations/authenticate.js +32 -0
  68. package/components/identity.tokens/operations/authenticate.js.map +1 -0
  69. package/components/identity.tokens/operations/decrypt.d.ts +3 -0
  70. package/components/identity.tokens/operations/decrypt.js +32 -0
  71. package/components/identity.tokens/operations/decrypt.js.map +1 -0
  72. package/components/identity.tokens/operations/encrypt.d.ts +8 -0
  73. package/components/identity.tokens/operations/encrypt.js +22 -0
  74. package/components/identity.tokens/operations/encrypt.js.map +1 -0
  75. package/components/identity.tokens/operations/revoke.d.ts +2 -0
  76. package/components/identity.tokens/operations/revoke.js +8 -0
  77. package/components/identity.tokens/operations/revoke.js.map +1 -0
  78. package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -0
  79. package/components/identity.tokens/operations/types.d.ts +40 -0
  80. package/components/identity.tokens/operations/types.js +3 -0
  81. package/components/identity.tokens/operations/types.js.map +1 -0
  82. package/components/octets.storage/manifest.toa.yaml +1 -0
  83. package/components/octets.storage/operations/store.js +3 -3
  84. package/cucumber.js +0 -1
  85. package/documentation/access.md +11 -11
  86. package/documentation/components.md +49 -13
  87. package/documentation/identity.md +14 -7
  88. package/documentation/io.md +56 -0
  89. package/documentation/octets.md +105 -40
  90. package/documentation/protocol.md +21 -1
  91. package/documentation/query.md +51 -6
  92. package/documentation/tree.md +22 -4
  93. package/documentation/vary.md +69 -0
  94. package/features/access.feature +13 -2
  95. package/features/annotation.feature +1 -0
  96. package/features/body.feature +3 -1
  97. package/features/cache.feature +3 -0
  98. package/features/cors.feature +72 -0
  99. package/features/directives.feature +2 -0
  100. package/features/dynamic.feature +14 -7
  101. package/features/errors.feature +4 -3
  102. package/features/etag.feature +97 -0
  103. package/features/identity.basic.feature +68 -0
  104. package/features/identity.feature +19 -3
  105. package/features/identity.federation.feature +153 -0
  106. package/features/identity.roles.feature +151 -0
  107. package/features/identity.tokens.feature +3 -0
  108. package/features/io.feature +167 -0
  109. package/features/octets.entries.feature +123 -0
  110. package/features/octets.feature +4 -28
  111. package/features/octets.meta.feature +66 -0
  112. package/features/octets.workflows.feature +177 -4
  113. package/features/queries.feature +9 -1
  114. package/features/response.feature +68 -0
  115. package/features/routes.feature +54 -10
  116. package/features/steps/Captures.ts +6 -0
  117. package/features/steps/Components.ts +18 -6
  118. package/features/steps/Database.ts +1 -1
  119. package/features/steps/Gateway.ts +4 -2
  120. package/features/steps/HTTP.ts +40 -87
  121. package/features/steps/IdP.ts +149 -0
  122. package/features/steps/Parameters.ts +8 -2
  123. package/features/steps/Workspace.ts +5 -7
  124. package/features/steps/components/echo/manifest.toa.yaml +1 -0
  125. package/features/steps/components/echo/operations/error.js +11 -0
  126. package/features/steps/components/greeter/manifest.toa.yaml +1 -0
  127. package/features/steps/components/octets.tester/manifest.toa.yaml +4 -0
  128. package/features/steps/components/octets.tester/operations/concat.js +7 -0
  129. package/features/steps/components/octets.tester/operations/echo.js +7 -0
  130. package/features/steps/components/pots/manifest.toa.yaml +12 -3
  131. package/features/steps/components/sequences/manifest.toa.yaml +1 -0
  132. package/features/steps/components/users/manifest.toa.yaml +4 -0
  133. package/features/steps/components/users.properties/manifest.toa.yaml +14 -0
  134. package/features/steps/tsconfig.json +1 -1
  135. package/features/timing.feature +66 -0
  136. package/features/vary.feature +180 -0
  137. package/package.json +16 -20
  138. package/readme.md +7 -6
  139. package/schemas/annotation.cos.yaml +1 -0
  140. package/schemas/io/input.cos.yaml +3 -0
  141. package/schemas/io/message.cos.yaml +5 -0
  142. package/schemas/io/output.cos.yaml +5 -0
  143. package/schemas/octets/delete.cos.yaml +2 -1
  144. package/schemas/octets/list.cos.yaml +2 -1
  145. package/schemas/octets/workflow.cos.yaml +12 -0
  146. package/schemas/querystring.cos.yaml +1 -0
  147. package/source/Annotation.ts +1 -0
  148. package/source/Context.ts +6 -4
  149. package/source/Directive.test.ts +14 -8
  150. package/source/Directive.ts +26 -49
  151. package/source/Endpoint.ts +53 -6
  152. package/source/Factory.ts +23 -12
  153. package/source/Gateway.ts +45 -42
  154. package/source/HTTP/Context.ts +67 -0
  155. package/source/HTTP/Server.test.ts +61 -134
  156. package/source/HTTP/Server.ts +96 -87
  157. package/source/HTTP/Timing.ts +40 -0
  158. package/source/HTTP/formats/msgpack.ts +9 -6
  159. package/source/HTTP/formats/text.ts +1 -1
  160. package/source/HTTP/formats/yaml.ts +1 -1
  161. package/source/HTTP/index.ts +1 -0
  162. package/source/HTTP/messages.test.ts +27 -8
  163. package/source/HTTP/messages.ts +38 -42
  164. package/source/Interception.ts +24 -0
  165. package/source/Mapping.ts +7 -8
  166. package/source/RTD/Context.ts +7 -10
  167. package/source/RTD/Directives.ts +28 -4
  168. package/source/RTD/Endpoint.ts +6 -4
  169. package/source/RTD/Match.ts +2 -7
  170. package/source/RTD/Method.ts +7 -13
  171. package/source/RTD/Node.ts +13 -14
  172. package/source/RTD/Tree.ts +19 -15
  173. package/source/RTD/factory.ts +2 -5
  174. package/source/RTD/syntax/parse.ts +6 -6
  175. package/source/RTD/syntax/types.ts +1 -1
  176. package/source/deployment.ts +7 -2
  177. package/source/directives/auth/Anonymous.ts +3 -2
  178. package/source/directives/auth/{Family.ts → Authorization.ts} +39 -40
  179. package/source/directives/auth/Delegate.ts +32 -0
  180. package/source/directives/auth/Incept.ts +11 -6
  181. package/source/directives/auth/Role.ts +5 -3
  182. package/source/directives/auth/Rule.ts +2 -2
  183. package/source/directives/auth/Scheme.ts +2 -2
  184. package/source/directives/auth/index.ts +2 -2
  185. package/source/directives/auth/schemes.ts +2 -1
  186. package/source/directives/auth/types.ts +9 -6
  187. package/source/directives/cache/{Family.ts → Cache.ts} +6 -7
  188. package/source/directives/cache/Control.ts +5 -5
  189. package/source/directives/cache/index.ts +2 -2
  190. package/source/directives/cache/types.ts +2 -2
  191. package/source/directives/cors/CORS.ts +62 -0
  192. package/source/directives/cors/index.ts +3 -0
  193. package/source/directives/dev/{Family.ts → Development.ts} +4 -5
  194. package/source/directives/dev/Stub.ts +4 -4
  195. package/source/directives/dev/Throw.ts +4 -4
  196. package/source/directives/dev/index.ts +2 -2
  197. package/source/directives/dev/types.ts +1 -1
  198. package/source/directives/index.ts +11 -6
  199. package/source/directives/io/Directive.ts +11 -0
  200. package/source/directives/io/IO.ts +43 -0
  201. package/source/directives/io/Input.ts +50 -0
  202. package/source/directives/io/Message.ts +1 -0
  203. package/source/directives/io/Output.ts +69 -0
  204. package/source/directives/io/index.ts +3 -0
  205. package/source/directives/io/schemas.ts +12 -0
  206. package/source/directives/octets/Context.ts +6 -5
  207. package/source/directives/octets/Delete.ts +64 -11
  208. package/source/directives/octets/Directive.ts +10 -0
  209. package/source/directives/octets/Fetch.ts +44 -29
  210. package/source/directives/octets/List.ts +50 -10
  211. package/source/directives/octets/{Family.ts → Octets.ts} +14 -9
  212. package/source/directives/octets/Permute.ts +18 -11
  213. package/source/directives/octets/Store.ts +70 -102
  214. package/source/directives/octets/Workflow.ts +48 -0
  215. package/source/directives/octets/index.ts +2 -2
  216. package/source/directives/octets/schemas.test.ts +21 -0
  217. package/source/directives/octets/schemas.ts +13 -6
  218. package/source/directives/octets/types.ts +2 -8
  219. package/source/directives/octets/workflows/Execution.ts +76 -0
  220. package/source/directives/octets/workflows/Workflow.ts +37 -0
  221. package/source/directives/octets/workflows/index.ts +1 -0
  222. package/source/directives/vary/Directive.ts +6 -0
  223. package/source/directives/vary/Embed.ts +62 -0
  224. package/source/directives/vary/Properties.ts +17 -0
  225. package/source/directives/vary/Vary.ts +48 -0
  226. package/source/directives/vary/embeddings/Embedding.ts +6 -0
  227. package/source/directives/vary/embeddings/Header.ts +32 -0
  228. package/source/directives/vary/embeddings/Language.ts +31 -0
  229. package/source/directives/vary/embeddings/index.ts +11 -0
  230. package/source/directives/vary/index.ts +3 -0
  231. package/source/exceptions.ts +13 -9
  232. package/source/io.ts +4 -0
  233. package/source/manifest.test.ts +6 -14
  234. package/source/manifest.ts +9 -6
  235. package/source/root.ts +5 -0
  236. package/source/schemas.ts +7 -3
  237. package/transpiled/Annotation.d.ts +8 -0
  238. package/transpiled/Annotation.js +3 -0
  239. package/transpiled/Annotation.js.map +1 -0
  240. package/transpiled/Branch.d.ts +7 -0
  241. package/transpiled/Branch.js +3 -0
  242. package/transpiled/Branch.js.map +1 -0
  243. package/transpiled/Composition.d.ts +14 -0
  244. package/transpiled/Composition.js +43 -0
  245. package/transpiled/Composition.js.map +1 -0
  246. package/transpiled/Context.d.ts +7 -0
  247. package/transpiled/Context.js +3 -0
  248. package/transpiled/Context.js.map +1 -0
  249. package/transpiled/Directive.d.ts +18 -0
  250. package/transpiled/Directive.js +75 -0
  251. package/transpiled/Directive.js.map +1 -0
  252. package/transpiled/Endpoint.d.ts +22 -0
  253. package/transpiled/Endpoint.js +101 -0
  254. package/transpiled/Endpoint.js.map +1 -0
  255. package/transpiled/Factory.d.ts +9 -0
  256. package/transpiled/Factory.js +73 -0
  257. package/transpiled/Factory.js.map +1 -0
  258. package/transpiled/Gateway.d.ts +18 -0
  259. package/transpiled/Gateway.js +92 -0
  260. package/transpiled/Gateway.js.map +1 -0
  261. package/transpiled/HTTP/Context.d.ts +24 -0
  262. package/transpiled/HTTP/Context.js +47 -0
  263. package/transpiled/HTTP/Context.js.map +1 -0
  264. package/transpiled/HTTP/Server.d.ts +25 -0
  265. package/transpiled/HTTP/Server.js +141 -0
  266. package/transpiled/HTTP/Server.js.map +1 -0
  267. package/transpiled/HTTP/Timing.d.ts +10 -0
  268. package/transpiled/HTTP/Timing.js +29 -0
  269. package/transpiled/HTTP/Timing.js.map +1 -0
  270. package/transpiled/HTTP/exceptions.d.ts +34 -0
  271. package/transpiled/HTTP/exceptions.js +71 -0
  272. package/transpiled/HTTP/exceptions.js.map +1 -0
  273. package/transpiled/HTTP/formats/index.d.ts +10 -0
  274. package/transpiled/HTTP/formats/index.js +38 -0
  275. package/transpiled/HTTP/formats/index.js.map +1 -0
  276. package/transpiled/HTTP/formats/json.d.ts +6 -0
  277. package/transpiled/HTTP/formats/json.js +17 -0
  278. package/transpiled/HTTP/formats/json.js.map +1 -0
  279. package/transpiled/HTTP/formats/msgpack.d.ts +6 -0
  280. package/transpiled/HTTP/formats/msgpack.js +17 -0
  281. package/transpiled/HTTP/formats/msgpack.js.map +1 -0
  282. package/transpiled/HTTP/formats/text.d.ts +8 -0
  283. package/transpiled/HTTP/formats/text.js +15 -0
  284. package/transpiled/HTTP/formats/text.js.map +1 -0
  285. package/transpiled/HTTP/formats/yaml.d.ts +6 -0
  286. package/transpiled/HTTP/formats/yaml.js +41 -0
  287. package/transpiled/HTTP/formats/yaml.js.map +1 -0
  288. package/transpiled/HTTP/index.d.ts +4 -0
  289. package/transpiled/HTTP/index.js +21 -0
  290. package/transpiled/HTTP/index.js.map +1 -0
  291. package/transpiled/HTTP/messages.d.ts +19 -0
  292. package/transpiled/HTTP/messages.js +73 -0
  293. package/transpiled/HTTP/messages.js.map +1 -0
  294. package/transpiled/Interception.d.ts +9 -0
  295. package/transpiled/Interception.js +19 -0
  296. package/transpiled/Interception.js.map +1 -0
  297. package/transpiled/Mapping.d.ts +8 -0
  298. package/transpiled/Mapping.js +38 -0
  299. package/transpiled/Mapping.js.map +1 -0
  300. package/transpiled/Query.d.ts +13 -0
  301. package/transpiled/Query.js +107 -0
  302. package/transpiled/Query.js.map +1 -0
  303. package/transpiled/RTD/Context.d.ts +12 -0
  304. package/transpiled/RTD/Context.js +3 -0
  305. package/transpiled/RTD/Context.js.map +1 -0
  306. package/transpiled/RTD/Directives.d.ts +22 -0
  307. package/transpiled/RTD/Directives.js +3 -0
  308. package/transpiled/RTD/Directives.js.map +1 -0
  309. package/transpiled/RTD/Endpoint.d.ts +11 -0
  310. package/transpiled/RTD/Endpoint.js +3 -0
  311. package/transpiled/RTD/Endpoint.js.map +1 -0
  312. package/transpiled/RTD/Match.d.ts +9 -0
  313. package/transpiled/RTD/Match.js +3 -0
  314. package/transpiled/RTD/Match.js.map +1 -0
  315. package/transpiled/RTD/Method.d.ts +9 -0
  316. package/transpiled/RTD/Method.js +16 -0
  317. package/transpiled/RTD/Method.js.map +1 -0
  318. package/transpiled/RTD/Node.d.ts +19 -0
  319. package/transpiled/RTD/Node.js +62 -0
  320. package/transpiled/RTD/Node.js.map +1 -0
  321. package/transpiled/RTD/Route.d.ts +14 -0
  322. package/transpiled/RTD/Route.js +49 -0
  323. package/transpiled/RTD/Route.js.map +1 -0
  324. package/transpiled/RTD/Tree.d.ts +14 -0
  325. package/transpiled/RTD/Tree.js +45 -0
  326. package/transpiled/RTD/Tree.js.map +1 -0
  327. package/transpiled/RTD/factory.d.ts +4 -0
  328. package/transpiled/RTD/factory.js +36 -0
  329. package/transpiled/RTD/factory.js.map +1 -0
  330. package/transpiled/RTD/index.d.ts +8 -0
  331. package/transpiled/RTD/index.js +38 -0
  332. package/transpiled/RTD/index.js.map +1 -0
  333. package/transpiled/RTD/segment.d.ts +8 -0
  334. package/transpiled/RTD/segment.js +25 -0
  335. package/transpiled/RTD/segment.js.map +1 -0
  336. package/transpiled/RTD/syntax/index.d.ts +2 -0
  337. package/transpiled/RTD/syntax/index.js +19 -0
  338. package/transpiled/RTD/syntax/index.js.map +1 -0
  339. package/transpiled/RTD/syntax/parse.d.ts +4 -0
  340. package/transpiled/RTD/syntax/parse.js +128 -0
  341. package/transpiled/RTD/syntax/parse.js.map +1 -0
  342. package/transpiled/RTD/syntax/types.d.ts +41 -0
  343. package/transpiled/RTD/syntax/types.js +5 -0
  344. package/transpiled/RTD/syntax/types.js.map +1 -0
  345. package/transpiled/Remotes.d.ts +9 -0
  346. package/transpiled/Remotes.js +25 -0
  347. package/transpiled/Remotes.js.map +1 -0
  348. package/transpiled/Tenant.d.ts +13 -0
  349. package/transpiled/Tenant.js +34 -0
  350. package/transpiled/Tenant.js.map +1 -0
  351. package/transpiled/deployment.d.ts +3 -0
  352. package/transpiled/deployment.js +71 -0
  353. package/transpiled/deployment.js.map +1 -0
  354. package/transpiled/directives/auth/Anonymous.d.ts +6 -0
  355. package/transpiled/directives/auth/Anonymous.js +16 -0
  356. package/transpiled/directives/auth/Anonymous.js.map +1 -0
  357. package/transpiled/directives/auth/Authorization.d.ts +19 -0
  358. package/transpiled/directives/auth/Authorization.js +127 -0
  359. package/transpiled/directives/auth/Authorization.js.map +1 -0
  360. package/transpiled/directives/auth/Delegate.d.ts +8 -0
  361. package/transpiled/directives/auth/Delegate.js +27 -0
  362. package/transpiled/directives/auth/Delegate.js.map +1 -0
  363. package/transpiled/directives/auth/Echo.d.ts +6 -0
  364. package/transpiled/directives/auth/Echo.js +13 -0
  365. package/transpiled/directives/auth/Echo.js.map +1 -0
  366. package/transpiled/directives/auth/Id.d.ts +7 -0
  367. package/transpiled/directives/auth/Id.js +17 -0
  368. package/transpiled/directives/auth/Id.js.map +1 -0
  369. package/transpiled/directives/auth/Incept.d.ts +10 -0
  370. package/transpiled/directives/auth/Incept.js +63 -0
  371. package/transpiled/directives/auth/Incept.js.map +1 -0
  372. package/transpiled/directives/auth/Role.d.ts +11 -0
  373. package/transpiled/directives/auth/Role.js +46 -0
  374. package/transpiled/directives/auth/Role.js.map +1 -0
  375. package/transpiled/directives/auth/Rule.d.ts +9 -0
  376. package/transpiled/directives/auth/Rule.js +22 -0
  377. package/transpiled/directives/auth/Rule.js.map +1 -0
  378. package/transpiled/directives/auth/Scheme.d.ts +7 -0
  379. package/transpiled/directives/auth/Scheme.js +47 -0
  380. package/transpiled/directives/auth/Scheme.js.map +1 -0
  381. package/transpiled/directives/auth/index.d.ts +2 -0
  382. package/transpiled/directives/auth/index.js +6 -0
  383. package/transpiled/directives/auth/index.js.map +1 -0
  384. package/transpiled/directives/auth/schemes.d.ts +3 -0
  385. package/transpiled/directives/auth/schemes.js +10 -0
  386. package/transpiled/directives/auth/schemes.js.map +1 -0
  387. package/transpiled/directives/auth/split.d.ts +2 -0
  388. package/transpiled/directives/auth/split.js +38 -0
  389. package/transpiled/directives/auth/split.js.map +1 -0
  390. package/transpiled/directives/auth/types.d.ts +31 -0
  391. package/transpiled/directives/auth/types.js +3 -0
  392. package/transpiled/directives/auth/types.js.map +1 -0
  393. package/transpiled/directives/cache/Cache.d.ts +11 -0
  394. package/transpiled/directives/cache/Cache.js +28 -0
  395. package/transpiled/directives/cache/Cache.js.map +1 -0
  396. package/transpiled/directives/cache/Control.d.ts +9 -0
  397. package/transpiled/directives/cache/Control.js +42 -0
  398. package/transpiled/directives/cache/Control.js.map +1 -0
  399. package/transpiled/directives/cache/Exact.d.ts +4 -0
  400. package/transpiled/directives/cache/Exact.js +11 -0
  401. package/transpiled/directives/cache/Exact.js.map +1 -0
  402. package/transpiled/directives/cache/index.d.ts +2 -0
  403. package/transpiled/directives/cache/index.js +6 -0
  404. package/transpiled/directives/cache/index.js.map +1 -0
  405. package/transpiled/directives/cache/types.d.ts +7 -0
  406. package/transpiled/directives/cache/types.js +3 -0
  407. package/transpiled/directives/cache/types.js.map +1 -0
  408. package/transpiled/directives/cors/CORS.d.ts +10 -0
  409. package/transpiled/directives/cors/CORS.js +51 -0
  410. package/transpiled/directives/cors/CORS.js.map +1 -0
  411. package/transpiled/directives/cors/index.d.ts +2 -0
  412. package/transpiled/directives/cors/index.js +6 -0
  413. package/transpiled/directives/cors/index.js.map +1 -0
  414. package/transpiled/directives/dev/Development.d.ts +9 -0
  415. package/transpiled/directives/dev/Development.js +29 -0
  416. package/transpiled/directives/dev/Development.js.map +1 -0
  417. package/transpiled/directives/dev/Stub.d.ts +7 -0
  418. package/transpiled/directives/dev/Stub.js +14 -0
  419. package/transpiled/directives/dev/Stub.js.map +1 -0
  420. package/transpiled/directives/dev/Throw.d.ts +7 -0
  421. package/transpiled/directives/dev/Throw.js +14 -0
  422. package/transpiled/directives/dev/Throw.js.map +1 -0
  423. package/transpiled/directives/dev/index.d.ts +2 -0
  424. package/transpiled/directives/dev/index.js +6 -0
  425. package/transpiled/directives/dev/index.js.map +1 -0
  426. package/transpiled/directives/dev/types.d.ts +4 -0
  427. package/transpiled/directives/dev/types.js +3 -0
  428. package/transpiled/directives/dev/types.js.map +1 -0
  429. package/transpiled/directives/index.d.ts +4 -0
  430. package/transpiled/directives/index.js +13 -0
  431. package/transpiled/directives/index.js.map +1 -0
  432. package/transpiled/directives/io/Directive.d.ts +8 -0
  433. package/transpiled/directives/io/Directive.js +3 -0
  434. package/transpiled/directives/io/Directive.js.map +1 -0
  435. package/transpiled/directives/io/IO.d.ts +9 -0
  436. package/transpiled/directives/io/IO.js +33 -0
  437. package/transpiled/directives/io/IO.js.map +1 -0
  438. package/transpiled/directives/io/Input.d.ts +11 -0
  439. package/transpiled/directives/io/Input.js +63 -0
  440. package/transpiled/directives/io/Input.js.map +1 -0
  441. package/transpiled/directives/io/Message.d.ts +1 -0
  442. package/transpiled/directives/io/Message.js +3 -0
  443. package/transpiled/directives/io/Message.js.map +1 -0
  444. package/transpiled/directives/io/Output.d.ts +13 -0
  445. package/transpiled/directives/io/Output.js +76 -0
  446. package/transpiled/directives/io/Output.js.map +1 -0
  447. package/transpiled/directives/io/index.d.ts +2 -0
  448. package/transpiled/directives/io/index.js +6 -0
  449. package/transpiled/directives/io/index.js.map +1 -0
  450. package/transpiled/directives/io/schemas.d.ts +7 -0
  451. package/transpiled/directives/io/schemas.js +14 -0
  452. package/transpiled/directives/io/schemas.js.map +1 -0
  453. package/transpiled/directives/octets/Context.d.ts +8 -0
  454. package/transpiled/directives/octets/Context.js +42 -0
  455. package/transpiled/directives/octets/Context.js.map +1 -0
  456. package/transpiled/directives/octets/Delete.d.ts +20 -0
  457. package/transpiled/directives/octets/Delete.js +84 -0
  458. package/transpiled/directives/octets/Delete.js.map +1 -0
  459. package/transpiled/directives/octets/Directive.d.ts +8 -0
  460. package/transpiled/directives/octets/Directive.js +8 -0
  461. package/transpiled/directives/octets/Directive.js.map +1 -0
  462. package/transpiled/directives/octets/Fetch.d.ts +18 -0
  463. package/transpiled/directives/octets/Fetch.js +92 -0
  464. package/transpiled/directives/octets/Fetch.js.map +1 -0
  465. package/transpiled/directives/octets/List.d.ts +16 -0
  466. package/transpiled/directives/octets/List.js +74 -0
  467. package/transpiled/directives/octets/List.js.map +1 -0
  468. package/transpiled/directives/octets/Octets.d.ts +12 -0
  469. package/transpiled/directives/octets/Octets.js +55 -0
  470. package/transpiled/directives/octets/Octets.js.map +1 -0
  471. package/transpiled/directives/octets/Permute.d.ts +11 -0
  472. package/transpiled/directives/octets/Permute.js +58 -0
  473. package/transpiled/directives/octets/Permute.js.map +1 -0
  474. package/transpiled/directives/octets/Store.d.ts +24 -0
  475. package/transpiled/directives/octets/Store.js +95 -0
  476. package/transpiled/directives/octets/Store.js.map +1 -0
  477. package/transpiled/directives/octets/Workflow.d.ts +15 -0
  478. package/transpiled/directives/octets/Workflow.js +59 -0
  479. package/transpiled/directives/octets/Workflow.js.map +1 -0
  480. package/transpiled/directives/octets/index.d.ts +2 -0
  481. package/transpiled/directives/octets/index.js +6 -0
  482. package/transpiled/directives/octets/index.js.map +1 -0
  483. package/transpiled/directives/octets/schemas.d.ts +13 -0
  484. package/transpiled/directives/octets/schemas.js +18 -0
  485. package/transpiled/directives/octets/schemas.js.map +1 -0
  486. package/transpiled/directives/octets/types.d.ts +5 -0
  487. package/transpiled/directives/octets/types.js +3 -0
  488. package/transpiled/directives/octets/types.js.map +1 -0
  489. package/transpiled/directives/octets/workflows/Execution.d.ts +25 -0
  490. package/transpiled/directives/octets/workflows/Execution.js +54 -0
  491. package/transpiled/directives/octets/workflows/Execution.js.map +1 -0
  492. package/transpiled/directives/octets/workflows/Workflow.d.ts +12 -0
  493. package/transpiled/directives/octets/workflows/Workflow.js +25 -0
  494. package/transpiled/directives/octets/workflows/Workflow.js.map +1 -0
  495. package/transpiled/directives/octets/workflows/index.d.ts +1 -0
  496. package/transpiled/directives/octets/workflows/index.js +6 -0
  497. package/transpiled/directives/octets/workflows/index.js.map +1 -0
  498. package/transpiled/directives/vary/Directive.d.ts +5 -0
  499. package/transpiled/directives/vary/Directive.js +3 -0
  500. package/transpiled/directives/vary/Directive.js.map +1 -0
  501. package/transpiled/directives/vary/Embed.d.ts +10 -0
  502. package/transpiled/directives/vary/Embed.js +49 -0
  503. package/transpiled/directives/vary/Embed.js.map +1 -0
  504. package/transpiled/directives/vary/Properties.d.ts +9 -0
  505. package/transpiled/directives/vary/Properties.js +16 -0
  506. package/transpiled/directives/vary/Properties.js.map +1 -0
  507. package/transpiled/directives/vary/Vary.d.ts +10 -0
  508. package/transpiled/directives/vary/Vary.js +36 -0
  509. package/transpiled/directives/vary/Vary.js.map +1 -0
  510. package/transpiled/directives/vary/embeddings/Embedding.d.ts +5 -0
  511. package/transpiled/directives/vary/embeddings/Embedding.js +3 -0
  512. package/transpiled/directives/vary/embeddings/Embedding.js.map +1 -0
  513. package/transpiled/directives/vary/embeddings/Header.d.ts +7 -0
  514. package/transpiled/directives/vary/embeddings/Header.js +28 -0
  515. package/transpiled/directives/vary/embeddings/Header.js.map +1 -0
  516. package/transpiled/directives/vary/embeddings/Language.d.ts +7 -0
  517. package/transpiled/directives/vary/embeddings/Language.js +28 -0
  518. package/transpiled/directives/vary/embeddings/Language.js.map +1 -0
  519. package/transpiled/directives/vary/embeddings/index.d.ts +5 -0
  520. package/transpiled/directives/vary/embeddings/index.js +10 -0
  521. package/transpiled/directives/vary/embeddings/index.js.map +1 -0
  522. package/transpiled/directives/vary/index.d.ts +2 -0
  523. package/transpiled/directives/vary/index.js +6 -0
  524. package/transpiled/directives/vary/index.js.map +1 -0
  525. package/transpiled/discovery.d.ts +1 -0
  526. package/transpiled/discovery.js +3 -0
  527. package/transpiled/discovery.js.map +1 -0
  528. package/transpiled/exceptions.d.ts +2 -0
  529. package/transpiled/exceptions.js +39 -0
  530. package/transpiled/exceptions.js.map +1 -0
  531. package/transpiled/index.d.ts +5 -0
  532. package/transpiled/index.js +12 -0
  533. package/transpiled/index.js.map +1 -0
  534. package/transpiled/io.d.ts +3 -0
  535. package/transpiled/io.js +3 -0
  536. package/transpiled/io.js.map +1 -0
  537. package/transpiled/manifest.d.ts +3 -0
  538. package/transpiled/manifest.js +66 -0
  539. package/transpiled/manifest.js.map +1 -0
  540. package/transpiled/root.d.ts +2 -0
  541. package/transpiled/root.js +44 -0
  542. package/transpiled/root.js.map +1 -0
  543. package/transpiled/schemas.d.ts +7 -0
  544. package/transpiled/schemas.js +14 -0
  545. package/transpiled/schemas.js.map +1 -0
  546. package/transpiled/tsconfig.tsbuildinfo +1 -0
  547. package/source/HTTP/Server.fixtures.ts +0 -41
@@ -1,199 +1,126 @@
1
+ import { randomUUID } from 'node:crypto'
1
2
  import { Connector } from '@toa.io/core'
2
- import { immediate } from '@toa.io/generic'
3
- import { generate } from 'randomstring'
4
3
  import { type Processing, Server } from './Server'
5
4
  import { type OutgoingMessage } from './messages'
6
- import { express, cors, createRequest, res, next } from './Server.fixtures'
7
5
  import { BadRequest } from './exceptions'
8
- import type { Express, Request, RequestHandler } from 'express'
9
- import type { CorsOptions } from 'cors'
10
- import type http from 'node:http'
11
-
12
- jest.mock('express', () => () => express())
13
- jest.mock('cors', () => (options: CorsOptions) => cors(options))
14
6
 
15
7
  let server: Server
16
- let app: jest.MockedObject<Express>
17
-
18
- beforeEach(() => {
19
- jest.clearAllMocks()
20
8
 
21
- server = Server.create()
22
- app = express.mock.results[0]?.value
9
+ beforeAll(() => {
10
+ server = Server.create({ port: 0 })
23
11
  })
24
12
 
25
13
  it('should instance of connector', async () => {
26
14
  expect(server).toBeInstanceOf(Connector)
27
15
  })
28
16
 
29
- it('should create express app', async () => {
30
- expect(express).toHaveBeenCalled()
31
- expect(app.disable).toHaveBeenCalledWith('x-powered-by')
32
- })
33
-
34
- it('should support cors', async () => {
35
- expect(cors).toHaveBeenCalledWith({ allowedHeaders: ['content-type'] } satisfies CorsOptions)
36
-
37
- const middleware = cors.mock.results[0].value
38
-
39
- expect(app.use).toHaveBeenCalledWith(middleware)
40
- })
41
-
42
17
  it('should start HTTP server', async () => {
43
- const stared = server.connect()
44
-
45
- await immediate()
46
-
47
- expect(app.listen).toHaveBeenCalledWith(8000, expect.anything())
48
-
49
- const done = app.listen.mock.calls[0][1]
50
-
51
- if (done !== undefined) done()
18
+ await server.connect()
52
19
 
53
- await stared
54
- })
55
-
56
- it('should stop HTTP server', async () => {
57
- const started = server.connect()
58
-
59
- await immediate()
60
-
61
- app.listen.mock.calls[0][1]?.() // `listen` callback
62
-
63
- await started
64
-
65
- const stopped = server.disconnect()
66
- const httpServer: jest.MockedObject<http.Server> = app.listen.mock.results[0].value
67
-
68
- await immediate()
69
-
70
- expect(httpServer.close).toHaveBeenCalled()
71
-
72
- httpServer.close.mock.calls[0][0]?.() // `close` callback
73
-
74
- await stopped
20
+ expect(server.connected).toBeTruthy()
21
+ expect(server.port).toBeGreaterThan(0)
75
22
  })
76
23
 
77
24
  it('should register request handler', async () => {
78
- const process = jest.fn(async () => ({})) as unknown as Processing
79
- const req = createRequest()
25
+ const process: Processing = jest.fn().mockResolvedValue(undefined)
80
26
 
81
27
  server.attach(process)
82
28
 
83
- await use(req)
29
+ const res = await fetch(`http://localhost:${server.port}`)
30
+
31
+ await res.text()
84
32
 
85
- expect(process).toHaveBeenCalled()
33
+ expect(process).toHaveBeenCalledTimes(1)
86
34
  })
87
35
 
88
36
  it('should send 501 on unknown method', async () => {
89
- const req = createRequest({ method: generate() })
37
+ const head = await fetch(`http://localhost:${server.port}/`, { method: 'COPY' })
90
38
 
91
- await use(req)
39
+ await head.text()
40
+ expect(head.status).toBe(501)
41
+ })
92
42
 
93
- expect(res.sendStatus).toHaveBeenCalledWith(501)
43
+ it('should stop HTTP server', async () => {
44
+ await server.connect()
45
+ await server.disconnect()
46
+ expect(server.connected).toBeFalsy()
94
47
  })
95
48
 
96
49
  describe('result', () => {
97
- it('should send status code 200 if the result has a value', async () => {
98
- const req = createRequest()
50
+ beforeEach(async () => {
51
+ server = Server.create({ port: 0 })
52
+ await server.connect()
53
+ })
54
+
55
+ afterEach(async () => {
56
+ await server.disconnect()
57
+ })
99
58
 
59
+ it('should send status code 200 if the result has a value', async () => {
100
60
  server.attach(async (): Promise<OutgoingMessage> => ({
101
- headers: new Headers(), body: generate()
61
+ headers: new Headers(), body: randomUUID()
102
62
  }))
103
- await use(req)
104
63
 
105
- expect(res.status).toHaveBeenCalledWith(200)
64
+ const res = await fetch(`http://localhost:${server.port}/`)
65
+
66
+ await res.text()
67
+ expect(res.status).toBe(200)
106
68
  })
107
69
 
108
70
  it('should send status code 204 if the result has no value', async () => {
109
- const req = createRequest()
110
-
111
71
  server.attach(async (): Promise<OutgoingMessage> => ({ headers: new Headers() }))
112
- await use(req)
113
72
 
114
- expect(res.status).toHaveBeenCalledWith(204)
73
+ const res = await fetch(`http://localhost:${server.port}/`)
74
+
75
+ await res.text()
76
+ expect(res.status).toBe(204)
115
77
  })
116
78
 
117
79
  it('should send result', async () => {
118
- const body = { [generate()]: generate() }
119
- const json = JSON.stringify(body)
120
- const buf = Buffer.from(json)
121
- const req = createRequest({ headers: { accept: 'application/json' } })
80
+ const body = { [randomUUID()]: randomUUID() }
122
81
 
123
- server.attach(async (): Promise<OutgoingMessage> => ({ headers: new Headers(), body }))
124
- await use(req)
82
+ server.attach(async (): Promise<OutgoingMessage> =>
83
+ ({ headers: new Headers(), body }))
125
84
 
126
- expect(res.end).toHaveBeenCalledWith(buf)
127
- })
85
+ const res = await fetch(`http://localhost:${server.port}/`,
86
+ { headers: { accept: 'application/json' } })
128
87
 
129
- it('should return 500 on exception', async () => {
130
- async function process (): Promise<OutgoingMessage> {
131
- throw new Error('Bad')
132
- }
88
+ const result = await res.json()
133
89
 
134
- const req = createRequest()
135
-
136
- server.attach(process)
137
- await use(req)
138
-
139
- expect(res.status).toHaveBeenCalledWith(500)
90
+ expect(result).toEqual(body)
140
91
  })
141
92
 
142
- it('should output exception message if debug is enabled', async () => {
143
- jest.clearAllMocks()
144
-
145
- server = Server.create({ debug: true })
146
- app = express.mock.results[0]?.value
147
-
148
- const message = generate()
149
- const req = createRequest()
150
-
151
- async function process (): Promise<OutgoingMessage> {
152
- throw new Error(message)
153
- }
93
+ it('should return 500 on exception', async () => {
94
+ server.attach(jest.fn().mockRejectedValue(new Error('Bad')))
154
95
 
155
- server.attach(process)
156
- await use(req)
96
+ const res = await fetch(`http://localhost:${server.port}/`)
157
97
 
158
- expect(res.status).toHaveBeenCalledWith(500)
98
+ await res.text()
99
+ expect(res.status).toBe(500)
159
100
  })
160
101
 
161
102
  it('should send client error', async () => {
162
- const req = createRequest()
163
- const message = generate()
103
+ const message = randomUUID()
164
104
 
165
- async function process (): Promise<OutgoingMessage> {
166
- throw new BadRequest(message)
167
- }
105
+ server.attach(jest.fn().mockRejectedValueOnce(new BadRequest(message)))
168
106
 
169
- server.attach(process)
170
- await use(req)
107
+ const res = await fetch(`http://localhost:${server.port}/`)
108
+ const text = await res.text()
171
109
 
172
- expect(res.status).toHaveBeenCalledWith(400)
110
+ expect(res.status).toBe(400)
111
+ expect(text).toContain(message)
173
112
  })
174
113
  })
175
114
 
176
115
  describe('options', () => {
177
116
  it('should send 501 on unspecified method', async () => {
178
- jest.clearAllMocks()
117
+ server = Server.create({ methods: new Set(['COPY']), port: 0 })
118
+ await server.connect()
179
119
 
180
- server = Server.create({ methods: new Set(['COPY']) })
181
- app = express.mock.results[0]?.value
120
+ const res = await fetch(`http://localhost:${server.port}/`)
182
121
 
183
- const req = createRequest({ method: 'GET' })
184
-
185
- await use(req)
186
-
187
- expect(res.sendStatus).toHaveBeenCalledWith(501)
122
+ await res.text()
123
+ await server.disconnect()
124
+ expect(res.status).toBe(501)
188
125
  })
189
126
  })
190
-
191
- async function use (req: Request): Promise<void> {
192
- for (const call of app.use.mock.calls) {
193
- const usage = call[0] as unknown as RequestHandler
194
-
195
- usage(req, res, next)
196
- }
197
-
198
- await immediate()
199
- }
@@ -1,149 +1,158 @@
1
- import express from 'express'
2
- import cors from 'cors'
1
+ import fs from 'node:fs'
2
+ import os from 'node:os'
3
+ import * as http from 'node:http'
4
+ import assert from 'node:assert'
5
+ import { once } from 'node:events'
3
6
  import { Connector } from '@toa.io/core'
4
7
  import { promex } from '@toa.io/generic'
5
- import Negotiator from 'negotiator'
6
- import { read, write, type IncomingMessage, type OutgoingMessage } from './messages'
8
+ import { type OutgoingMessage, write } from './messages'
7
9
  import { ClientError, Exception } from './exceptions'
8
- import { formats, types } from './formats'
9
- import type { Format } from './formats'
10
- import type * as http from 'node:http'
11
- import type { Express, Request, Response, NextFunction } from 'express'
10
+ import { Context } from './Context'
11
+ import type { IncomingMessage } from './Context'
12
12
 
13
13
  export class Server extends Connector {
14
- private readonly debug: boolean
15
- private readonly app: Express
16
- private server?: http.Server
14
+ private readonly server: http.Server = http.createServer()
15
+ private readonly properties: Properties
16
+ private process?: Processing
17
17
 
18
- private constructor (app: Express, debug: boolean) {
18
+ private constructor (properties: Properties) {
19
19
  super()
20
20
 
21
- this.app = app
22
- this.debug = debug
21
+ this.properties = properties
22
+
23
+ this.server.on('request', (req, res) => this.listener(req, res))
23
24
  }
24
25
 
25
- public static create (options: Partial<Properties> = {}): Server {
26
- const properties: Properties = Object.assign({}, defaults(), options)
26
+ public get port (): number {
27
+ if (this.properties.port !== 0)
28
+ return this.properties.port
29
+
30
+ const address = this.server.address()
31
+
32
+ if (address === null || typeof address === 'string')
33
+ throw new Error('Server is not listening on a port.')
27
34
 
28
- const app = express()
35
+ return address.port
36
+ }
29
37
 
30
- app.disable('x-powered-by')
31
- app.use(cors({ allowedHeaders: ['content-type'] }))
32
- app.use(supportedMethods(properties.methods))
38
+ public static create (options?: Partial<Properties>): Server {
39
+ const properties = options === undefined
40
+ ? DEFAULTS
41
+ : { ...DEFAULTS, ...options }
33
42
 
34
- return new Server(app, properties.debug)
43
+ return new Server(properties)
35
44
  }
36
45
 
37
46
  public attach (process: Processing): void {
38
- this.app.use((request: any, response: Response): void => {
39
- this.extend(request)
40
- .then(process)
41
- .then(this.success(request, response))
42
- .catch(this.fail(request, response))
43
- })
47
+ this.process = process
44
48
  }
45
49
 
46
50
  protected override async open (): Promise<void> {
47
- const listening = promex()
48
-
49
- this.server = this.app.listen(8000, listening.callback)
51
+ this.server.listen(this.properties.port)
50
52
 
51
- await listening
53
+ await once(this.server, 'listening')
52
54
 
53
55
  console.info('HTTP Server is listening.')
54
56
  }
55
57
 
56
58
  protected override async close (): Promise<void> {
57
- const stopped = promex()
59
+ this.server.close()
58
60
 
59
- this.server?.close(stopped.callback)
61
+ console.info('HTTP Server stopped accepting new connections.')
60
62
 
61
- await stopped
62
- }
63
+ await once(this.server, 'close')
63
64
 
64
- protected override dispose (): void {
65
65
  console.info('HTTP Server has been stopped.')
66
66
  }
67
67
 
68
- private async extend (request: IncomingMessage): Promise<IncomingMessage> {
69
- const message = request as unknown as IncomingMessage
68
+ private listener (request: http.IncomingMessage, response: http.ServerResponse): void {
69
+ if (request.method === undefined || !this.properties.methods.has(request.method)) {
70
+ response.writeHead(501).end()
71
+
72
+ return
73
+ }
74
+
75
+ if (request.url === undefined) {
76
+ response.writeHead(400).end()
77
+
78
+ return
79
+ }
80
+
81
+ assert.ok(this.process !== undefined,
82
+ 'No processing function has been attached to the server.')
70
83
 
71
- message.encoder = negotiate(request)
72
- message.parse = async <T> (): Promise<T> => await read(request)
84
+ const context = new Context(request as IncomingMessage, this.properties.trace)
73
85
 
74
- return message
86
+ this.process(context)
87
+ .then(this.success(context, response))
88
+ .catch(this.fail(context, response))
75
89
  }
76
90
 
77
- private success (request: IncomingMessage, response: Response) {
91
+ private success (context: Context, response: http.ServerResponse) {
78
92
  return (message: OutgoingMessage) => {
79
93
  let status = message.status
80
94
 
81
95
  if (status === undefined)
82
- if (message.body === null) status = 404
83
- else if (request.method === 'POST') status = 201
84
- else if (message.body === undefined) status = 204
85
- else status = 200
86
-
87
- response.status(status)
88
- message.headers?.forEach((value, key) => response.set(key, value))
89
-
90
- if (message.body !== undefined && message.body !== null)
91
- write(request, response, message)
92
- else
93
- response.end()
96
+ if (message.body === null)
97
+ status = 404
98
+ else if (context.request.method === 'POST')
99
+ status = 201
100
+ else if (message.body === undefined)
101
+ status = 204
102
+ else
103
+ status = 200
104
+
105
+ response.statusCode = message.status = status
106
+ write(context, response, message)
94
107
  }
95
108
  }
96
109
 
97
- private fail (request: IncomingMessage, response: Response) {
98
- return (exception: Error) => {
99
- const status = exception instanceof Exception
110
+ private fail (context: Context, response: http.ServerResponse) {
111
+ return async (exception: Error) => {
112
+ if (!context.request.complete)
113
+ await adam(context.request)
114
+
115
+ response.statusCode = exception instanceof Exception
100
116
  ? exception.status
101
117
  : 500
102
118
 
103
- response.status(status)
104
-
105
- const outputAllowed = exception instanceof ClientError || this.debug
119
+ const message: OutgoingMessage = { status: response.statusCode }
120
+ const verbose = exception instanceof ClientError || this.properties.debug
106
121
 
107
- if (outputAllowed) {
108
- const body = exception instanceof Exception
122
+ if (verbose)
123
+ message.body = exception instanceof Exception
109
124
  ? exception.body
110
125
  : (exception.stack ?? exception.message)
111
126
 
112
- write(request, response, { body })
113
- } else
114
- response.end()
115
-
116
- // stop accepting request
117
- if (!request.complete)
118
- request.destroy()
127
+ write(context, response, message)
119
128
  }
120
129
  }
121
130
  }
122
131
 
123
- function supportedMethods (methods: Set<string>) {
124
- return (req: Request, res: Response, next: NextFunction): void => {
125
- if (methods.has(req.method)) next()
126
- else res.sendStatus(501)
127
- }
128
- }
132
+ // https://github.com/whatwg/fetch/issues/1254
133
+ async function adam (request: http.IncomingMessage): Promise<void> {
134
+ const completed = promex()
135
+ const devnull = fs.createWriteStream(os.devNull)
129
136
 
130
- function negotiate (request: Request): Format | null {
131
- const negotiator = new Negotiator(request)
132
- const mediaType = negotiator.mediaType(types)
137
+ request
138
+ .on('end', completed.callback)
139
+ .pipe(devnull)
133
140
 
134
- return mediaType === undefined ? null : formats[mediaType]
141
+ return completed
142
+ }
143
+
144
+ const DEFAULTS: Properties = {
145
+ methods: new Set<string>(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),
146
+ debug: false,
147
+ trace: false,
148
+ port: 8000
135
149
  }
136
150
 
137
151
  interface Properties {
138
152
  methods: Set<string>
139
153
  debug: boolean
154
+ trace: boolean
155
+ port: number
140
156
  }
141
157
 
142
- function defaults (): Properties {
143
- return {
144
- methods: new Set<string>(['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']),
145
- debug: false
146
- }
147
- }
148
-
149
- export type Processing = (input: IncomingMessage) => Promise<OutgoingMessage>
158
+ 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
+ }
@@ -1,13 +1,16 @@
1
1
  import { type Buffer } from 'node:buffer'
2
- import * as msgpack from 'msgpackr'
3
-
4
- export const type = 'application/msgpack'
5
- export const multipart = 'multipart/msgpack'
2
+ import { pack, unpack } from 'msgpackr'
6
3
 
7
4
  export function decode (buffer: Buffer): any {
8
- return msgpack.decode(buffer)
5
+ return unpack(buffer)
9
6
  }
10
7
 
11
8
  export function encode (value: any): Buffer {
12
- return msgpack.encode(value)
9
+ if (typeof value === 'object' && value !== null)
10
+ Object.setPrototypeOf(value, null)
11
+
12
+ return pack(value)
13
13
  }
14
+
15
+ export const type = 'application/msgpack'
16
+ export const multipart = 'multipart/msgpack'
@@ -7,6 +7,6 @@ export function decode (buffer: Buffer): any {
7
7
  return buffer.toString()
8
8
  }
9
9
 
10
- export function encode (value: any): Buffer {
10
+ export function encode (value: { toString: () => string }): Buffer {
11
11
  return Buffer.from(value.toString())
12
12
  }
@@ -11,7 +11,7 @@ export function decode (buffer: Buffer): any {
11
11
  }
12
12
 
13
13
  export function encode (value: any): Buffer {
14
- const text = yaml.dump(value)
14
+ const text = yaml.dump(value, { lineWidth: -1, noRefs: true })
15
15
 
16
16
  return Buffer.from(text)
17
17
  }
@@ -1,3 +1,4 @@
1
1
  export * from './Server'
2
2
  export * from './messages'
3
3
  export * from './exceptions'
4
+ export * from './Context'
@@ -1,8 +1,10 @@
1
+ import { Readable } from 'node:stream'
1
2
  import { generate } from 'randomstring'
2
3
  import * as msgpack from 'msgpackr'
3
4
  import { read } from './messages'
4
- import { createRequest } from './Server.fixtures'
5
5
  import { BadRequest, UnsupportedMediaType } from './exceptions'
6
+ import { Timing } from './Timing'
7
+ import type { Context } from './Context'
6
8
 
7
9
  beforeEach(() => {
8
10
  jest.clearAllMocks()
@@ -14,8 +16,8 @@ describe('read', () => {
14
16
  const headers = { 'content-type': 'application/json' }
15
17
  const input = { [generate()]: generate() }
16
18
  const json = JSON.stringify(input)
17
- const request = createRequest({ path, headers }, json)
18
- const output = await read(request)
19
+ const context = createContext(path, headers, json)
20
+ const output = await read(context)
19
21
 
20
22
  expect(output).toStrictEqual(input)
21
23
  })
@@ -24,7 +26,7 @@ describe('read', () => {
24
26
  const path = generate()
25
27
  const headers = { 'content-type': 'application/yaml' }
26
28
  const yaml = 'foo: 1'
27
- const request = createRequest({ path, headers }, yaml)
29
+ const request = createContext(path, headers, yaml)
28
30
  const value = await read(request)
29
31
 
30
32
  expect(value).toStrictEqual({ foo: 1 })
@@ -35,7 +37,7 @@ describe('read', () => {
35
37
  const headers = { 'content-type': 'application/msgpack' }
36
38
  const input = { [generate()]: generate() }
37
39
  const msg = msgpack.encode(input)
38
- const request = createRequest({ path, headers }, msg)
40
+ const request = createContext(path, headers, msg)
39
41
  const output = await read(request)
40
42
 
41
43
  expect(output).toStrictEqual(input)
@@ -45,7 +47,7 @@ describe('read', () => {
45
47
  const path = generate()
46
48
  const headers = { 'content-type': 'text/plain' }
47
49
  const input = generate()
48
- const request = createRequest({ path, headers }, input)
50
+ const request = createContext(path, headers, input)
49
51
  const output = await read(request)
50
52
 
51
53
  expect(output).toStrictEqual(input)
@@ -54,7 +56,7 @@ describe('read', () => {
54
56
  it('should throw on unsupported request media type', async () => {
55
57
  const path = generate()
56
58
  const headers = { 'content-type': 'wtf/' + generate() }
57
- const request = createRequest({ path, headers })
59
+ const request = createContext(path, headers)
58
60
 
59
61
  await expect(read(request)).rejects.toThrow(UnsupportedMediaType)
60
62
  })
@@ -63,8 +65,25 @@ describe('read', () => {
63
65
  const path = generate()
64
66
  const text = '{ "foo": "val... oops '
65
67
  const headers = { 'content-type': 'application/json' }
66
- const request = createRequest({ path, headers }, text)
68
+ const request = createContext(path, headers, text)
67
69
 
68
70
  await expect(read(request)).rejects.toThrow(BadRequest)
69
71
  })
70
72
  })
73
+
74
+ export function createContext
75
+ (url: string, headers: Record<string, string> = {}, content: string | Buffer = ''):
76
+ jest.MockedObject<Context> {
77
+ const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content)
78
+ const stream = Readable.from(buffer)
79
+
80
+ const mock: Partial<Context> = {
81
+ request: Object.assign(stream, {
82
+ url,
83
+ headers
84
+ }) as unknown as Context['request'],
85
+ timing: new Timing(false)
86
+ }
87
+
88
+ return mock as unknown as jest.MockedObject<Context>
89
+ }