@toa.io/extensions.exposition 1.0.0-alpha.7 → 1.0.0-alpha.71

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 (434) hide show
  1. package/components/context.toa.yaml +2 -2
  2. package/components/identity.bans/manifest.toa.yaml +15 -7
  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 -10
  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 +26 -0
  15. package/components/identity.basic/operations/incept.js.map +1 -0
  16. package/components/identity.basic/operations/transit.d.ts +4 -4
  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 +8 -4
  21. package/components/identity.basic/source/authenticate.ts +16 -5
  22. package/components/identity.basic/source/incept.ts +38 -0
  23. package/components/identity.basic/source/transit.ts +8 -6
  24. package/components/identity.basic/source/types.ts +8 -4
  25. package/components/identity.federation/manifest.toa.yaml +32 -16
  26. package/components/identity.federation/operations/authenticate.d.ts +2 -2
  27. package/components/identity.federation/operations/authenticate.js +4 -11
  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/assertions-as-values.js +2 -1
  33. package/components/identity.federation/operations/lib/assertions-as-values.js.map +1 -1
  34. package/components/identity.federation/operations/lib/jwt.d.ts +5 -5
  35. package/components/identity.federation/operations/lib/jwt.js +25 -12
  36. package/components/identity.federation/operations/lib/jwt.js.map +1 -1
  37. package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
  38. package/components/identity.federation/operations/types/configuration.d.ts +14 -0
  39. package/components/identity.federation/operations/types/configuration.js +3 -0
  40. package/components/identity.federation/operations/types/configuration.js.map +1 -0
  41. package/components/identity.federation/operations/{types.d.ts → types/context.d.ts} +15 -7
  42. package/components/identity.federation/operations/types/context.js +3 -0
  43. package/components/identity.federation/operations/types/context.js.map +1 -0
  44. package/components/identity.federation/operations/types/entity.d.ts +6 -0
  45. package/components/identity.federation/operations/types/entity.js +3 -0
  46. package/components/identity.federation/operations/types/entity.js.map +1 -0
  47. package/components/identity.federation/operations/types/index.d.ts +3 -0
  48. package/components/identity.federation/operations/types/index.js +20 -0
  49. package/components/identity.federation/operations/types/index.js.map +1 -0
  50. package/components/identity.federation/source/authenticate.ts +6 -19
  51. package/components/identity.federation/source/{create.ts → incept.ts} +10 -9
  52. package/components/identity.federation/source/lib/assertions-as-values.ts +4 -2
  53. package/components/identity.federation/source/lib/jwt.test.ts +123 -4
  54. package/components/identity.federation/source/lib/jwt.ts +36 -16
  55. package/components/identity.federation/source/types/configuration.ts +15 -0
  56. package/components/identity.federation/source/{types.ts → types/context.ts} +17 -6
  57. package/components/identity.federation/source/types/entity.ts +6 -0
  58. package/components/identity.federation/source/types/index.ts +3 -0
  59. package/components/identity.federation/tsconfig.json +5 -4
  60. package/components/identity.roles/manifest.toa.yaml +18 -7
  61. package/components/identity.roles/operations/grant.d.ts +10 -0
  62. package/components/identity.roles/operations/grant.js +21 -0
  63. package/components/identity.roles/operations/grant.js.map +1 -0
  64. package/components/identity.roles/operations/lib/Entity.d.ts +5 -0
  65. package/components/identity.roles/operations/lib/Entity.js +3 -0
  66. package/components/identity.roles/operations/lib/Entity.js.map +1 -0
  67. package/components/identity.roles/operations/list.d.ts +1 -4
  68. package/components/identity.roles/operations/list.js.map +1 -1
  69. package/components/identity.roles/operations/principal.d.ts +4 -6
  70. package/components/identity.roles/operations/principal.js +6 -1
  71. package/components/identity.roles/operations/principal.js.map +1 -1
  72. package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
  73. package/components/identity.roles/source/grant.ts +32 -0
  74. package/components/identity.roles/source/lib/Entity.ts +5 -0
  75. package/components/identity.roles/source/list.ts +2 -4
  76. package/components/identity.roles/source/principal.ts +10 -8
  77. package/components/identity.tokens/manifest.toa.yaml +19 -5
  78. package/components/identity.tokens/operations/authenticate.d.ts +2 -2
  79. package/components/identity.tokens/operations/authenticate.js +12 -5
  80. package/components/identity.tokens/operations/authenticate.js.map +1 -1
  81. package/components/identity.tokens/operations/decrypt.js +1 -0
  82. package/components/identity.tokens/operations/decrypt.js.map +1 -1
  83. package/components/identity.tokens/operations/encrypt.js +5 -1
  84. package/components/identity.tokens/operations/encrypt.js.map +1 -1
  85. package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
  86. package/components/identity.tokens/operations/types.d.ts +8 -2
  87. package/components/identity.tokens/receivers/identity.bans.created.js +3 -0
  88. package/components/identity.tokens/source/authenticate.test.ts +11 -4
  89. package/components/identity.tokens/source/authenticate.ts +14 -6
  90. package/components/identity.tokens/source/decrypt.test.ts +5 -3
  91. package/components/identity.tokens/source/decrypt.ts +9 -8
  92. package/components/identity.tokens/source/encrypt.test.ts +26 -2
  93. package/components/identity.tokens/source/encrypt.ts +5 -1
  94. package/components/identity.tokens/source/types.ts +9 -2
  95. package/components/octets.storage/manifest.toa.yaml +6 -7
  96. package/components/octets.storage/operations/get.js +2 -2
  97. package/components/octets.storage/operations/store.js +113 -3
  98. package/documentation/access.md +75 -38
  99. package/documentation/authorities.md +49 -0
  100. package/documentation/cache.md +8 -1
  101. package/documentation/components.md +47 -22
  102. package/documentation/flow.md +31 -0
  103. package/documentation/identity.md +17 -22
  104. package/documentation/introspection.md +82 -0
  105. package/documentation/octets.md +81 -23
  106. package/documentation/protocol.md +13 -3
  107. package/documentation/query.md +29 -4
  108. package/documentation/require.md +15 -0
  109. package/documentation/tree.md +13 -0
  110. package/documentation/vary.md +14 -14
  111. package/features/access.feature +78 -46
  112. package/features/annotation.feature +1 -0
  113. package/features/auth.claim.feature +170 -0
  114. package/features/authorities.basic.feature +141 -0
  115. package/features/authorities.feature +32 -0
  116. package/features/authorities.federation.feature +100 -0
  117. package/features/authorities.tokens.feature +117 -0
  118. package/features/body.feature +3 -0
  119. package/features/cache.feature +109 -5
  120. package/features/cors.feature +6 -1
  121. package/features/debug.feature +34 -0
  122. package/features/directives.feature +3 -0
  123. package/features/dynamic.feature +4 -0
  124. package/features/errors.feature +20 -7
  125. package/features/etag.feature +31 -0
  126. package/features/flow.feature +45 -0
  127. package/features/identity.bans.feature +137 -0
  128. package/features/identity.basic.feature +125 -23
  129. package/features/identity.feature +7 -2
  130. package/features/identity.federation.feature +66 -11
  131. package/features/identity.roles.feature +250 -7
  132. package/features/identity.tokens.feature +54 -4
  133. package/features/introspection.feature +153 -0
  134. package/features/io.feature +38 -1
  135. package/features/methods.feature +47 -0
  136. package/features/octets.download.feature +189 -0
  137. package/features/octets.entries.feature +8 -1
  138. package/features/octets.feature +82 -54
  139. package/features/octets.meta.feature +3 -0
  140. package/features/octets.workflows.feature +239 -19
  141. package/features/probes.feature +14 -0
  142. package/features/{queries.feature → query.feature} +65 -2
  143. package/features/realtime.feature +34 -0
  144. package/features/require.feature +67 -0
  145. package/features/response.feature +38 -3
  146. package/features/routes.feature +93 -2
  147. package/features/steps/Database.ts +17 -10
  148. package/features/steps/Gateway.ts +23 -6
  149. package/features/steps/IdP.ts +30 -25
  150. package/features/steps/Parameters.ts +4 -1
  151. package/features/steps/Realtime.ts +151 -0
  152. package/features/steps/components/echo/manifest.toa.yaml +14 -1
  153. package/features/steps/components/echo/operations/identity.js +7 -0
  154. package/features/steps/components/echo/operations/parameters.js +7 -0
  155. package/features/steps/components/echo.beacon/manifest.toa.yaml +2 -0
  156. package/features/steps/components/echo.beacon/operations/hello.js +5 -0
  157. package/features/steps/components/octets.tester/manifest.toa.yaml +22 -1
  158. package/features/steps/components/octets.tester/operations/authority.js +7 -0
  159. package/features/steps/components/octets.tester/operations/baz.js +1 -2
  160. package/features/steps/components/octets.tester/operations/diversify.js +3 -1
  161. package/features/steps/components/octets.tester/operations/foo.js +2 -2
  162. package/features/steps/components/octets.tester/operations/redirect.js +12 -0
  163. package/features/steps/components/octets.tester/operations/yex.js +16 -0
  164. package/features/steps/components/octets.tester/operations/yield.js +13 -0
  165. package/features/steps/components/pots/manifest.toa.yaml +14 -3
  166. package/features/steps/components/users/manifest.toa.yaml +0 -1
  167. package/features/steps/components/users.properties/manifest.toa.yaml +1 -1
  168. package/features/streams.feature +5 -0
  169. package/features/timing.feature +4 -1
  170. package/features/vary.feature +71 -0
  171. package/package.json +23 -14
  172. package/readme.md +19 -14
  173. package/schemas/annotation.cos.yaml +1 -1
  174. package/schemas/method.cos.yaml +1 -1
  175. package/schemas/node.cos.yaml +1 -0
  176. package/schemas/octets/store.cos.yaml +25 -3
  177. package/schemas/query.cos.yaml +4 -10
  178. package/source/Annotation.ts +3 -3
  179. package/source/Composition.ts +0 -6
  180. package/source/Directive.ts +4 -5
  181. package/source/Endpoint.ts +52 -12
  182. package/source/Factory.ts +10 -11
  183. package/source/Gateway.ts +48 -19
  184. package/source/HTTP/Context.ts +25 -2
  185. package/source/HTTP/Server.ts +52 -44
  186. package/source/HTTP/exceptions.ts +13 -1
  187. package/source/HTTP/formats/index.ts +3 -3
  188. package/source/HTTP/messages.test.ts +45 -2
  189. package/source/HTTP/messages.ts +23 -5
  190. package/source/Introspection.ts +11 -0
  191. package/source/Mapping.ts +63 -21
  192. package/source/Query.test.ts +3 -3
  193. package/source/Query.ts +117 -33
  194. package/source/RTD/Endpoint.ts +3 -0
  195. package/source/RTD/Method.ts +16 -0
  196. package/source/RTD/Node.ts +29 -13
  197. package/source/RTD/Route.ts +5 -4
  198. package/source/RTD/factory.ts +5 -2
  199. package/source/RTD/syntax/parse.ts +37 -24
  200. package/source/RTD/syntax/types.ts +6 -4
  201. package/source/Remotes.ts +2 -9
  202. package/source/Tenant.ts +0 -8
  203. package/source/deployment.ts +33 -23
  204. package/source/directives/auth/Authorization.ts +37 -14
  205. package/source/directives/auth/Delegate.ts +42 -0
  206. package/source/directives/auth/Federation.ts +84 -0
  207. package/source/directives/auth/Incept.ts +4 -3
  208. package/source/directives/auth/Role.test.ts +53 -6
  209. package/source/directives/auth/Role.ts +22 -14
  210. package/source/directives/auth/split.ts +1 -1
  211. package/source/directives/auth/types.ts +1 -1
  212. package/source/directives/cache/Cache.ts +13 -6
  213. package/source/directives/cache/Control.ts +42 -16
  214. package/source/directives/cors/CORS.ts +1 -1
  215. package/source/directives/dev/Development.ts +1 -1
  216. package/source/directives/flow/Fetch.ts +88 -0
  217. package/source/directives/flow/Flow.ts +34 -0
  218. package/source/directives/flow/index.ts +3 -0
  219. package/source/directives/flow/types.ts +6 -0
  220. package/source/directives/index.ts +3 -1
  221. package/source/directives/io/Input.ts +4 -4
  222. package/source/directives/io/Output.ts +4 -3
  223. package/source/directives/octets/Context.ts +3 -2
  224. package/source/directives/octets/Fetch.ts +11 -10
  225. package/source/directives/octets/List.ts +5 -5
  226. package/source/directives/octets/Octets.ts +1 -3
  227. package/source/directives/octets/Store.ts +30 -10
  228. package/source/directives/octets/bytes.test.ts +30 -0
  229. package/source/directives/octets/bytes.ts +18 -0
  230. package/source/directives/octets/schemas.ts +4 -6
  231. package/source/directives/octets/workflows/Execution.ts +60 -8
  232. package/source/directives/octets/workflows/Workflow.ts +2 -1
  233. package/source/directives/require/Directive.ts +5 -0
  234. package/source/directives/require/Headers.ts +20 -0
  235. package/source/directives/require/Require.ts +28 -0
  236. package/source/directives/require/index.ts +3 -0
  237. package/source/directives/vary/Directive.ts +2 -1
  238. package/source/directives/vary/Embed.ts +14 -8
  239. package/source/directives/vary/Vary.ts +6 -4
  240. package/source/directives/vary/embeddings/Authority.ts +8 -0
  241. package/source/directives/vary/embeddings/Embedding.ts +2 -1
  242. package/source/directives/vary/embeddings/Parameter.ts +14 -0
  243. package/source/directives/vary/embeddings/index.ts +6 -4
  244. package/source/exceptions.ts +23 -11
  245. package/source/manifest.ts +10 -11
  246. package/source/schemas.ts +1 -1
  247. package/transpiled/Annotation.d.ts +3 -3
  248. package/transpiled/Composition.d.ts +0 -1
  249. package/transpiled/Composition.js +0 -4
  250. package/transpiled/Composition.js.map +1 -1
  251. package/transpiled/Directive.js +4 -4
  252. package/transpiled/Directive.js.map +1 -1
  253. package/transpiled/Endpoint.d.ts +6 -4
  254. package/transpiled/Endpoint.js +32 -4
  255. package/transpiled/Endpoint.js.map +1 -1
  256. package/transpiled/Factory.d.ts +1 -1
  257. package/transpiled/Factory.js +9 -8
  258. package/transpiled/Factory.js.map +1 -1
  259. package/transpiled/Gateway.d.ts +2 -0
  260. package/transpiled/Gateway.js +36 -12
  261. package/transpiled/Gateway.js.map +1 -1
  262. package/transpiled/HTTP/Context.d.ts +8 -1
  263. package/transpiled/HTTP/Context.js +16 -2
  264. package/transpiled/HTTP/Context.js.map +1 -1
  265. package/transpiled/HTTP/Server.d.ts +13 -2
  266. package/transpiled/HTTP/Server.js +39 -36
  267. package/transpiled/HTTP/Server.js.map +1 -1
  268. package/transpiled/HTTP/exceptions.d.ts +7 -1
  269. package/transpiled/HTTP/exceptions.js +13 -1
  270. package/transpiled/HTTP/exceptions.js.map +1 -1
  271. package/transpiled/HTTP/formats/index.js +3 -3
  272. package/transpiled/HTTP/formats/index.js.map +1 -1
  273. package/transpiled/HTTP/messages.d.ts +1 -0
  274. package/transpiled/HTTP/messages.js +24 -5
  275. package/transpiled/HTTP/messages.js.map +1 -1
  276. package/transpiled/Introspection.d.ts +9 -0
  277. package/transpiled/Introspection.js +3 -0
  278. package/transpiled/Introspection.js.map +1 -0
  279. package/transpiled/Mapping.d.ts +10 -2
  280. package/transpiled/Mapping.js +48 -19
  281. package/transpiled/Mapping.js.map +1 -1
  282. package/transpiled/Query.d.ts +10 -1
  283. package/transpiled/Query.js +83 -30
  284. package/transpiled/Query.js.map +1 -1
  285. package/transpiled/RTD/Endpoint.d.ts +1 -0
  286. package/transpiled/RTD/Method.d.ts +4 -0
  287. package/transpiled/RTD/Method.js +11 -0
  288. package/transpiled/RTD/Method.js.map +1 -1
  289. package/transpiled/RTD/Node.d.ts +4 -1
  290. package/transpiled/RTD/Node.js +23 -12
  291. package/transpiled/RTD/Node.js.map +1 -1
  292. package/transpiled/RTD/Route.d.ts +1 -1
  293. package/transpiled/RTD/Route.js +0 -1
  294. package/transpiled/RTD/Route.js.map +1 -1
  295. package/transpiled/RTD/factory.js +5 -2
  296. package/transpiled/RTD/factory.js.map +1 -1
  297. package/transpiled/RTD/syntax/parse.js +34 -22
  298. package/transpiled/RTD/syntax/parse.js.map +1 -1
  299. package/transpiled/RTD/syntax/types.d.ts +5 -3
  300. package/transpiled/RTD/syntax/types.js +1 -1
  301. package/transpiled/RTD/syntax/types.js.map +1 -1
  302. package/transpiled/Remotes.d.ts +2 -4
  303. package/transpiled/Remotes.js +0 -5
  304. package/transpiled/Remotes.js.map +1 -1
  305. package/transpiled/Tenant.d.ts +0 -1
  306. package/transpiled/Tenant.js +0 -6
  307. package/transpiled/Tenant.js.map +1 -1
  308. package/transpiled/deployment.d.ts +1 -1
  309. package/transpiled/deployment.js +28 -20
  310. package/transpiled/deployment.js.map +1 -1
  311. package/transpiled/directives/auth/Authorization.js +26 -10
  312. package/transpiled/directives/auth/Authorization.js.map +1 -1
  313. package/transpiled/directives/auth/Delegate.d.ts +10 -0
  314. package/transpiled/directives/auth/Delegate.js +34 -0
  315. package/transpiled/directives/auth/Delegate.js.map +1 -0
  316. package/transpiled/directives/auth/Federation.d.ts +16 -0
  317. package/transpiled/directives/auth/Federation.js +57 -0
  318. package/transpiled/directives/auth/Federation.js.map +1 -0
  319. package/transpiled/directives/auth/Incept.js +4 -3
  320. package/transpiled/directives/auth/Incept.js.map +1 -1
  321. package/transpiled/directives/auth/Role.d.ts +4 -1
  322. package/transpiled/directives/auth/Role.js +20 -14
  323. package/transpiled/directives/auth/Role.js.map +1 -1
  324. package/transpiled/directives/auth/split.js +1 -1
  325. package/transpiled/directives/auth/split.js.map +1 -1
  326. package/transpiled/directives/cache/Cache.d.ts +3 -3
  327. package/transpiled/directives/cache/Cache.js +10 -4
  328. package/transpiled/directives/cache/Cache.js.map +1 -1
  329. package/transpiled/directives/cache/Control.d.ts +2 -1
  330. package/transpiled/directives/cache/Control.js +29 -12
  331. package/transpiled/directives/cache/Control.js.map +1 -1
  332. package/transpiled/directives/cors/CORS.js +1 -1
  333. package/transpiled/directives/cors/CORS.js.map +1 -1
  334. package/transpiled/directives/dev/Development.js +1 -1
  335. package/transpiled/directives/dev/Development.js.map +1 -1
  336. package/transpiled/directives/flow/Fetch.d.ts +13 -0
  337. package/transpiled/directives/flow/Fetch.js +59 -0
  338. package/transpiled/directives/flow/Fetch.js.map +1 -0
  339. package/transpiled/directives/flow/Flow.d.ts +10 -0
  340. package/transpiled/directives/flow/Flow.js +27 -0
  341. package/transpiled/directives/flow/Flow.js.map +1 -0
  342. package/transpiled/directives/flow/index.d.ts +2 -0
  343. package/transpiled/directives/flow/index.js +6 -0
  344. package/transpiled/directives/flow/index.js.map +1 -0
  345. package/transpiled/directives/flow/types.d.ts +5 -0
  346. package/transpiled/directives/flow/types.js.map +1 -0
  347. package/transpiled/directives/index.js +3 -1
  348. package/transpiled/directives/index.js.map +1 -1
  349. package/transpiled/directives/io/Input.js +2 -2
  350. package/transpiled/directives/io/Input.js.map +1 -1
  351. package/transpiled/directives/io/Output.js +2 -2
  352. package/transpiled/directives/io/Output.js.map +1 -1
  353. package/transpiled/directives/octets/Context.js +4 -24
  354. package/transpiled/directives/octets/Context.js.map +1 -1
  355. package/transpiled/directives/octets/Fetch.d.ts +3 -3
  356. package/transpiled/directives/octets/Fetch.js +8 -8
  357. package/transpiled/directives/octets/Fetch.js.map +1 -1
  358. package/transpiled/directives/octets/List.d.ts +3 -3
  359. package/transpiled/directives/octets/List.js +3 -3
  360. package/transpiled/directives/octets/List.js.map +1 -1
  361. package/transpiled/directives/octets/Octets.js +1 -3
  362. package/transpiled/directives/octets/Octets.js.map +1 -1
  363. package/transpiled/directives/octets/Store.d.ts +6 -1
  364. package/transpiled/directives/octets/Store.js +17 -7
  365. package/transpiled/directives/octets/Store.js.map +1 -1
  366. package/transpiled/directives/octets/bytes.d.ts +1 -0
  367. package/transpiled/directives/octets/bytes.js +21 -0
  368. package/transpiled/directives/octets/bytes.js.map +1 -0
  369. package/transpiled/directives/octets/schemas.d.ts +4 -6
  370. package/transpiled/directives/octets/schemas.js +1 -3
  371. package/transpiled/directives/octets/schemas.js.map +1 -1
  372. package/transpiled/directives/octets/workflows/Execution.d.ts +5 -1
  373. package/transpiled/directives/octets/workflows/Execution.js +44 -9
  374. package/transpiled/directives/octets/workflows/Execution.js.map +1 -1
  375. package/transpiled/directives/octets/workflows/Workflow.js +2 -1
  376. package/transpiled/directives/octets/workflows/Workflow.js.map +1 -1
  377. package/transpiled/directives/require/Directive.d.ts +4 -0
  378. package/transpiled/directives/require/Directive.js +3 -0
  379. package/transpiled/directives/require/Directive.js.map +1 -0
  380. package/transpiled/directives/require/Headers.d.ts +7 -0
  381. package/transpiled/directives/require/Headers.js +19 -0
  382. package/transpiled/directives/require/Headers.js.map +1 -0
  383. package/transpiled/directives/require/Require.d.ts +9 -0
  384. package/transpiled/directives/require/Require.js +27 -0
  385. package/transpiled/directives/require/Require.js.map +1 -0
  386. package/transpiled/directives/require/index.d.ts +2 -0
  387. package/transpiled/directives/require/index.js +6 -0
  388. package/transpiled/directives/require/index.js.map +1 -0
  389. package/transpiled/directives/vary/Directive.d.ts +2 -1
  390. package/transpiled/directives/vary/Embed.d.ts +2 -1
  391. package/transpiled/directives/vary/Embed.js +8 -6
  392. package/transpiled/directives/vary/Embed.js.map +1 -1
  393. package/transpiled/directives/vary/Vary.d.ts +2 -2
  394. package/transpiled/directives/vary/Vary.js +3 -3
  395. package/transpiled/directives/vary/Vary.js.map +1 -1
  396. package/transpiled/directives/vary/embeddings/Authority.d.ts +5 -0
  397. package/transpiled/directives/vary/embeddings/Authority.js +10 -0
  398. package/transpiled/directives/vary/embeddings/Authority.js.map +1 -0
  399. package/transpiled/directives/vary/embeddings/Embedding.d.ts +2 -1
  400. package/transpiled/directives/vary/embeddings/Parameter.d.ts +7 -0
  401. package/transpiled/directives/vary/embeddings/Parameter.js +14 -0
  402. package/transpiled/directives/vary/embeddings/Parameter.js.map +1 -0
  403. package/transpiled/directives/vary/embeddings/index.d.ts +2 -2
  404. package/transpiled/directives/vary/embeddings/index.js +8 -4
  405. package/transpiled/directives/vary/embeddings/index.js.map +1 -1
  406. package/transpiled/exceptions.d.ts +3 -2
  407. package/transpiled/exceptions.js +14 -7
  408. package/transpiled/exceptions.js.map +1 -1
  409. package/transpiled/manifest.js +10 -11
  410. package/transpiled/manifest.js.map +1 -1
  411. package/transpiled/schemas.d.ts +1 -1
  412. package/transpiled/schemas.js +2 -2
  413. package/transpiled/schemas.js.map +1 -1
  414. package/transpiled/tsconfig.tsbuildinfo +1 -1
  415. package/tsconfig.json +9 -7
  416. package/components/identity.basic/operations/create.d.ts +0 -10
  417. package/components/identity.basic/operations/create.js +0 -10
  418. package/components/identity.basic/operations/create.js.map +0 -1
  419. package/components/identity.basic/source/create.ts +0 -18
  420. package/components/identity.federation/operations/create.d.ts +0 -10
  421. package/components/identity.federation/operations/create.js.map +0 -1
  422. package/components/identity.federation/operations/schemas.d.ts +0 -59
  423. package/components/identity.federation/operations/schemas.js +0 -9
  424. package/components/identity.federation/operations/schemas.js.map +0 -1
  425. package/components/identity.federation/operations/types.js.map +0 -1
  426. package/components/identity.federation/source/schemas.ts +0 -61
  427. package/components/octets.storage/operations/permute.js +0 -7
  428. package/schemas/octets/context.cos.yaml +0 -1
  429. package/source/HTTP/Server.test.ts +0 -126
  430. package/source/directives/octets/Permute.ts +0 -44
  431. package/transpiled/directives/octets/Permute.d.ts +0 -11
  432. package/transpiled/directives/octets/Permute.js +0 -58
  433. package/transpiled/directives/octets/Permute.js.map +0 -1
  434. /package/{components/identity.federation/operations → transpiled/directives/flow}/types.js +0 -0
@@ -1,10 +1,10 @@
1
1
  import fs from 'node:fs'
2
2
  import os from 'node:os'
3
3
  import * as http from 'node:http'
4
- import assert from 'node:assert'
5
4
  import { once } from 'node:events'
5
+ import { setTimeout } from 'node:timers/promises'
6
+ import { console } from 'openspan'
6
7
  import { Connector } from '@toa.io/core'
7
- import { promex } from '@toa.io/generic'
8
8
  import { type OutgoingMessage, write } from './messages'
9
9
  import { ClientError, Exception } from './exceptions'
10
10
  import { Context } from './Context'
@@ -13,32 +13,22 @@ import type { IncomingMessage } from './Context'
13
13
  export class Server extends Connector {
14
14
  private readonly server: http.Server = http.createServer()
15
15
  private readonly properties: Properties
16
+ private readonly authorities: Record<string, string>
16
17
  private process?: Processing
18
+ private ready: boolean = false
19
+ private startedAt: number = 0
17
20
 
18
21
  private constructor (properties: Properties) {
19
22
  super()
20
23
 
21
24
  this.properties = properties
25
+ this.authorities = Object.fromEntries(Object.entries(properties.authorities).map(([key, value]) => [value, key]))
22
26
 
23
27
  this.server.on('request', (req, res) => this.listener(req, res))
24
28
  }
25
29
 
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.')
34
-
35
- return address.port
36
- }
37
-
38
- public static create (options?: Partial<Properties>): Server {
39
- const properties = options === undefined
40
- ? DEFAULTS
41
- : { ...DEFAULTS, ...options }
30
+ public static create (options: Options): Server {
31
+ const properties: Properties = Object.assign({}, DEFAULTS, options)
42
32
 
43
33
  return new Server(properties)
44
34
  }
@@ -48,21 +38,29 @@ export class Server extends Connector {
48
38
  }
49
39
 
50
40
  protected override async open (): Promise<void> {
41
+ this.startedAt = Date.now()
51
42
  this.server.listen(this.properties.port)
52
43
 
53
44
  await once(this.server, 'listening')
54
45
 
55
- console.info('HTTP Server is listening.')
46
+ console.info('HTTP Server is listening')
47
+
48
+ await setTimeout(this.properties.delay)
49
+
50
+ this.ready = true
51
+
52
+ console.info('Ready')
56
53
  }
57
54
 
58
55
  protected override async close (): Promise<void> {
59
56
  this.server.close()
57
+ this.ready = false
60
58
 
61
- console.info('HTTP Server stopped accepting new connections.')
59
+ console.info('Stopped accepting new connections')
62
60
 
63
61
  await once(this.server, 'close')
64
62
 
65
- console.info('HTTP Server has been stopped.')
63
+ console.info('Stopped')
66
64
  }
67
65
 
68
66
  private listener (request: http.IncomingMessage, response: http.ServerResponse): void {
@@ -72,18 +70,23 @@ export class Server extends Connector {
72
70
  return
73
71
  }
74
72
 
75
- if (request.url === undefined) {
76
- response.writeHead(400).end()
73
+ if (request.url === '/.ready') {
74
+ if (this.ready)
75
+ response.writeHead(200, { 'cache-control': 'no-store' }).end()
76
+ else {
77
+ const remaining = (Math.ceil((Date.now() - this.startedAt) / 1000)).toString()
78
+
79
+ response.writeHead(503, { 'retry-after': remaining }).end()
80
+ }
77
81
 
78
82
  return
79
83
  }
80
84
 
81
- assert.ok(this.process !== undefined,
82
- 'No processing function has been attached to the server.')
83
-
84
- const context = new Context(request as IncomingMessage, this.properties.trace)
85
+ const host = request.headers.host!
86
+ const authority = this.authorities[host] ?? host
87
+ const context = new Context(authority, request as IncomingMessage, this.properties)
85
88
 
86
- this.process(context)
89
+ this.process!(context)
87
90
  .then(this.success(context, response))
88
91
  .catch(this.fail(context, response))
89
92
  }
@@ -112,17 +115,15 @@ export class Server extends Connector {
112
115
  if (!context.request.complete)
113
116
  await adam(context.request)
114
117
 
115
- response.statusCode = exception instanceof Exception
116
- ? exception.status
117
- : 500
118
+ response.statusCode = exception instanceof Exception ? exception.status : 500
118
119
 
119
120
  const message: OutgoingMessage = { status: response.statusCode }
120
- const verbose = exception instanceof ClientError || this.properties.debug
121
121
 
122
- if (verbose)
123
- message.body = exception instanceof Exception
124
- ? exception.body
125
- : (exception.stack ?? exception.message)
122
+ if (exception instanceof ClientError || this.properties.debug)
123
+ message.body =
124
+ exception instanceof Exception
125
+ ? exception.body
126
+ : exception.stack ?? exception.message
126
127
 
127
128
  write(context, response, message)
128
129
  }
@@ -131,28 +132,35 @@ export class Server extends Connector {
131
132
 
132
133
  // https://github.com/whatwg/fetch/issues/1254
133
134
  async function adam (request: http.IncomingMessage): Promise<void> {
134
- const completed = promex()
135
135
  const devnull = fs.createWriteStream(os.devNull)
136
136
 
137
- request
138
- .on('end', completed.callback)
139
- .pipe(devnull)
137
+ request.pipe(devnull)
140
138
 
141
- return completed
139
+ await once(request, 'end')
142
140
  }
143
141
 
144
- const DEFAULTS: Properties = {
145
- methods: new Set<string>(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),
142
+ export const PORT = 8000
143
+ export const DELAY = 3 // seconds
144
+
145
+ const DEFAULTS: Omit<Properties, 'authorities'> = {
146
+ methods: new Set<string>(['OPTIONS', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'LOCK', 'UNLOCK']),
146
147
  debug: false,
147
148
  trace: false,
148
- port: 8000
149
+ port: PORT,
150
+ delay: DELAY * 1000
149
151
  }
150
152
 
151
153
  interface Properties {
154
+ authorities: Record<string, string>
152
155
  methods: Set<string>
153
156
  debug: boolean
154
157
  trace: boolean
155
158
  port: number
159
+ delay: number
160
+ }
161
+
162
+ export type Options = { authorities: Properties['authorities'] } & {
163
+ [K in Exclude<keyof Properties, 'authorities'>]?: Properties[K]
156
164
  }
157
165
 
158
166
  export type Processing = (input: Context) => Promise<OutgoingMessage>
@@ -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)
@@ -65,3 +71,9 @@ export class PreconditionFailed extends ClientError {
65
71
  super(412)
66
72
  }
67
73
  }
74
+
75
+ export class RequestEntityTooLarge extends ClientError {
76
+ public constructor (body?: any) {
77
+ super(413, body)
78
+ }
79
+ }
@@ -5,10 +5,10 @@ import * as msgpack from './msgpack'
5
5
  import * as text from './text'
6
6
 
7
7
  export const formats: Record<string, Format> = {
8
- [msgpack.type]: msgpack,
9
- [yaml.type]: yaml,
10
8
  [json.type]: json,
11
- [text.type]: text
9
+ [yaml.type]: yaml,
10
+ [text.type]: text,
11
+ [msgpack.type]: msgpack
12
12
  }
13
13
 
14
14
  export const types = Object.keys(formats)
@@ -1,9 +1,13 @@
1
- import { Readable } from 'node:stream'
1
+ import { PassThrough, Readable } from 'node:stream'
2
+ import * as streamConsumers from 'node:stream/consumers'
3
+ import { once } from 'node:events'
2
4
  import { generate } from 'randomstring'
3
5
  import * as msgpack from 'msgpackr'
4
- import { read } from './messages'
6
+ import { multipart, read, type OutgoingMessage } from './messages'
5
7
  import { BadRequest, UnsupportedMediaType } from './exceptions'
8
+ import { formats } from './formats'
6
9
  import { Timing } from './Timing'
10
+ import type * as http from 'node:http'
7
11
  import type { Context } from './Context'
8
12
 
9
13
  beforeEach(() => {
@@ -69,6 +73,45 @@ describe('read', () => {
69
73
 
70
74
  await expect(read(request)).rejects.toThrow(BadRequest)
71
75
  })
76
+
77
+ it('should output correct mulitpart format', async () => {
78
+ const response = new class extends PassThrough {
79
+ public readonly headers = new Headers()
80
+
81
+ public setHeader (key: string, value: string): this {
82
+ this.headers.set(key, value)
83
+
84
+ return this
85
+ }
86
+ }()
87
+
88
+ const context = { encoder: formats['text/plain'] } as unknown as Context
89
+ const message = { body: Readable.from(['Hello', 'New', 'World']) } as unknown as OutgoingMessage
90
+
91
+ multipart(message, context, response as unknown as http.ServerResponse)
92
+
93
+ await once(message.body, 'end')
94
+
95
+ const result = await streamConsumers.text(response)
96
+
97
+ expect(result).toBe([
98
+ '--cut',
99
+ '',
100
+ 'ACK',
101
+ '--cut',
102
+ '',
103
+ 'Hello',
104
+ '--cut',
105
+ '',
106
+ 'New',
107
+ '--cut',
108
+ '',
109
+ 'World',
110
+ '--cut',
111
+ '',
112
+ 'FIN',
113
+ '--cut--'].join('\r\n'))
114
+ })
72
115
  })
73
116
 
74
117
  export function createContext
@@ -1,5 +1,6 @@
1
1
  import { Readable } from 'node:stream'
2
2
  import { buffer } from 'node:stream/consumers'
3
+ import { console } from 'openspan'
3
4
  import { formats } from './formats'
4
5
  import { BadRequest, NotAcceptable, UnsupportedMediaType } from './exceptions'
5
6
  import type { Context } from './Context'
@@ -66,13 +67,13 @@ function stream
66
67
  else
67
68
  multipart(message, context, response)
68
69
 
69
- message.body.on('error', (e: Error) => {
70
- console.error(e)
70
+ message.body.on('error', (exception: Error) => {
71
+ console.error('Stream error', { path: context.url.pathname, exception })
71
72
  response.end()
72
73
  })
73
74
  }
74
75
 
75
- function multipart
76
+ export function multipart
76
77
  (message: OutgoingMessage, context: Context, response: http.ServerResponse): void {
77
78
  if (context.encoder === null)
78
79
  throw new NotAcceptable()
@@ -81,9 +82,26 @@ function multipart
81
82
 
82
83
  response.setHeader('content-type', `${encoder.multipart}; boundary=${BOUNDARY}`)
83
84
 
85
+ response.write(Buffer.concat([
86
+ CUT,
87
+ CRLF,
88
+ encoder.encode('ACK'),
89
+ CRLF,
90
+ CUT
91
+ ]))
92
+
84
93
  message.body
85
- .map((part: unknown) => Buffer.concat([CUT, encoder.encode(part), CRLF]))
86
- .on('end', () => response.end(FINALCUT))
94
+ .map((part: unknown) => Buffer.concat([
95
+ CRLF /* indicates no boundary headers */,
96
+ encoder.encode(part),
97
+ CRLF,
98
+ CUT]))
99
+ .on('end', () => response.end(Buffer.concat([
100
+ CRLF,
101
+ encoder.encode('FIN'),
102
+ CRLF,
103
+ FINALCUT
104
+ ])))
87
105
  .pipe(response)
88
106
  }
89
107
 
@@ -0,0 +1,11 @@
1
+ import type { Remote } from '@toa.io/core'
2
+
3
+ export interface Introspection {
4
+ route?: Record<string, Schema>
5
+ query?: Record<string, Schema>
6
+ input?: Schema
7
+ output?: Schema
8
+ errors?: string[]
9
+ }
10
+
11
+ export type Schema = Awaited<ReturnType<Remote['explain']>>['input']
package/source/Mapping.ts CHANGED
@@ -1,50 +1,92 @@
1
1
  import { type Parameter } from './RTD'
2
2
  import { Query } from './Query'
3
+ import type { Introspection, Schema } from './Introspection'
4
+ import type { QueryString } from './Query'
3
5
  import type * as http from './HTTP'
4
6
  import type * as syntax from './RTD/syntax'
5
7
  import type * as core from '@toa.io/core'
6
8
 
7
9
  export abstract class Mapping {
8
- public static create (query?: syntax.Query): Mapping {
9
- if (query === undefined || query === null)
10
- return new InputMapping()
10
+ protected readonly query: Query
11
11
 
12
- const q = new Query(query)
12
+ public constructor (query: Query) {
13
+ this.query = query
14
+ }
15
+
16
+ public static create (query?: syntax.Query | null): Mapping {
17
+ const q = new Query(query!)
13
18
 
14
- return new QueryableMapping(q)
19
+ return queryable(query)
20
+ ? new QueryableMapping(q)
21
+ : new InputMapping(q)
15
22
  }
16
23
 
17
- public abstract fit (input: any, qs: http.Query, parameters: Parameter[]): core.Request
24
+ public explain (introspection: Introspection): Record<string, Schema> | null {
25
+ return this.query.explain(introspection)
26
+ }
27
+
28
+ protected assign (input: any, qs: QueryString): void {
29
+ if (qs.parameters !== null) {
30
+ if (typeof input !== 'object' || input === null)
31
+ throw new Error('Input must be an object to embed query parameters')
32
+
33
+ Object.assign(input, qs.parameters)
34
+ }
35
+ }
36
+
37
+ public abstract fit (input: any, query: http.Query, parameters: Parameter[]): core.Request
18
38
  }
19
39
 
20
40
  class QueryableMapping extends Mapping {
21
- private readonly query: Query
41
+ public fit (input: any, query: http.Query, parameters: Parameter[]): core.Request {
42
+ const request: core.Request = {}
43
+ const qs = this.query.fit(query, parameters)
22
44
 
23
- public constructor (query: Query) {
24
- super()
45
+ if (input === undefined && qs.parameters !== null)
46
+ input = {}
25
47
 
26
- this.query = query
27
- }
48
+ this.assign(input, qs)
28
49
 
29
- public fit (input: any, qs: http.Query, parameters: Parameter[]): core.Request {
30
- const query = this.query.fit(qs, parameters)
50
+ if (input !== undefined)
51
+ request.input = input
31
52
 
32
- return {
33
- input,
34
- query
35
- }
53
+ if (qs.query !== null)
54
+ request.query = qs.query
55
+
56
+ return request
36
57
  }
37
58
  }
38
59
 
39
60
  class InputMapping extends Mapping {
40
- public fit (input: any, _: unknown, parameters: Parameter[]): core.Request {
41
- if (input === undefined && parameters.length > 0)
61
+ public fit (input: any, query: http.Query, parameters: Parameter[]): core.Request {
62
+ const request: core.Request = {}
63
+ const qs = this.query.fit(query, parameters)
64
+
65
+ if (input === undefined && (parameters.length > 0 || qs.parameters !== null))
42
66
  input = {}
43
67
 
44
- if (typeof input === 'object' && input !== null)
68
+ if (parameters.length > 0) {
69
+ if (typeof input !== 'object' || input === null)
70
+ throw new Error('Input must be an object to embed route parameters')
71
+
45
72
  for (const parameter of parameters)
46
73
  input[parameter.name] = parameter.value
74
+ }
47
75
 
48
- return { input }
76
+ this.assign(input, qs)
77
+
78
+ if (input !== undefined)
79
+ request.input = input
80
+
81
+ return request
49
82
  }
50
83
  }
84
+
85
+ export function queryable (query?: syntax.Query | null): boolean {
86
+ if (query === undefined || query === null)
87
+ return false
88
+
89
+ const keys = Object.keys(query)
90
+
91
+ return !(keys.length === 1 && keys[0] === 'parameters')
92
+ }
@@ -16,7 +16,7 @@ it('should combine request criteria', async () => {
16
16
  const instance = new Query(query)
17
17
  const result = instance.fit({ criteria: 'qux==4' }, parameters)
18
18
 
19
- expect(result.criteria).toStrictEqual('(foo==1);(bar==2;baz==3);(qux==4)')
19
+ expect(result.query!.criteria).toStrictEqual('(bar==2;baz==3);(foo==1);(qux==4)')
20
20
  })
21
21
 
22
22
  it('should set id parameter as query.id', async () => {
@@ -32,6 +32,6 @@ it('should set id parameter as query.id', async () => {
32
32
  const instance = new Query(query)
33
33
  const result = instance.fit({}, parameters)
34
34
 
35
- expect(result.criteria).toBeUndefined()
36
- expect(result.id).toStrictEqual(id)
35
+ expect(result.query!.criteria).toBeUndefined()
36
+ expect(result.query!.id).toStrictEqual(id)
37
37
  })
package/source/Query.ts CHANGED
@@ -1,43 +1,111 @@
1
+ import assert from 'node:assert'
1
2
  import * as http from './HTTP'
2
3
  import { type Parameter } from './RTD'
3
4
  import * as schemas from './schemas'
5
+ import { queryable } from './Mapping'
6
+ import type { Introspection, Schema } from './Introspection'
4
7
  import type * as syntax from './RTD/syntax'
5
8
  import type * as core from '@toa.io/core'
6
9
 
7
10
  export class Query {
8
11
  private readonly query: syntax.Query
9
12
  private readonly closed: boolean = false
13
+ private readonly prepend: ',' | ';' = ';'
14
+ private readonly queryable: boolean
10
15
 
11
16
  public constructor (query: syntax.Query) {
12
- if (query.criteria !== undefined) {
13
- const open = query.criteria[query.criteria.length - 1] === ';'
14
-
15
- if (open) query.criteria = query.criteria.slice(0, -1)
16
- else this.closed = true
17
+ this.queryable = queryable(query)
18
+
19
+ if (this.queryable) {
20
+ query.omit ??= { value: 0, range: [0, 1000] }
21
+ query.limit ??= { value: 10, range: [1, 100] }
22
+
23
+ if (query.criteria !== undefined) {
24
+ // eslint-disable-next-line max-depth
25
+ if (query.criteria.endsWith(';'))
26
+ query.criteria = query.criteria.slice(0, -1)
27
+ else
28
+ this.closed = true
29
+
30
+ // eslint-disable-next-line max-depth
31
+ if (query.criteria.startsWith(',') || query.criteria.startsWith(';')) {
32
+ this.prepend = query.criteria[0] as ',' | ';'
33
+
34
+ query.criteria = query.criteria.slice(1)
35
+ }
36
+ }
17
37
  }
18
38
 
19
39
  this.query = query
20
40
  }
21
41
 
22
- public fit (query: http.Query, parameters: Parameter[]): core.Query {
23
- const error = schemas.querystring.fit(query)
42
+ public fit (query: http.Query, parameters: Parameter[]): QueryString {
43
+ const qs = this.split(query)
44
+
45
+ if (qs.query !== null) {
46
+ const error = schemas.querystring.fit(qs.query)
24
47
 
25
- if (error !== null)
26
- throw new http.BadRequest('Query ' + error.message)
48
+ if (error !== null)
49
+ throw new http.BadRequest('Query ' + error.message)
27
50
 
28
- this.fitCriteria(query, parameters)
29
- this.fitRanges(query)
30
- this.fitSort(query)
51
+ this.fitCriteria(qs.query, parameters)
52
+ this.fitRanges(qs.query)
53
+ this.fitSort(qs.query)
54
+ }
31
55
 
32
- return query as core.Query
56
+ return {
57
+ query: qs.query as core.Query,
58
+ parameters: qs.parameters
59
+ }
33
60
  }
34
61
 
35
- private fitCriteria (query: http.Query, parameters: Parameter[]): void {
36
- const criteria: string[] = []
62
+ public explain (introspection: Introspection): Record<string, Schema> | null {
63
+ if (this.query?.parameters === undefined || introspection.input?.type !== 'object')
64
+ return null
37
65
 
38
- if (this.query.criteria !== undefined)
39
- criteria.push(this.query.criteria)
66
+ let query: Record<string, Schema> | null = null
67
+
68
+ for (const parameter of this.query.parameters) {
69
+ const schema = introspection.input.properties[parameter]
70
+
71
+ if (schema !== undefined) {
72
+ query ??= {}
73
+ query[parameter] = schema
74
+ }
75
+
76
+ delete introspection.input.properties[parameter]
77
+ }
78
+
79
+ return query
80
+ }
81
+
82
+ private split (query: http.Query): {
83
+ query: http.Query | null
84
+ parameters: Record<string, string> | null
85
+ } {
86
+ let parameters: Record<string, string> | null = null
87
+
88
+ if (this.query?.parameters !== undefined)
89
+ for (const key in query)
90
+ // eslint-disable-next-line max-depth
91
+ if (this.query.parameters.includes(key)) {
92
+ parameters ??= {}
93
+ parameters[key] = query[key] as string
94
+
95
+ delete query[key]
96
+ }
40
97
 
98
+ if (!this.queryable)
99
+ query = null!
100
+
101
+ return {
102
+ query,
103
+ parameters
104
+ }
105
+ }
106
+
107
+ private fitCriteria (query: http.Query, parameters: Parameter[]): void {
108
+ const groups: CriteriaGroup[] = []
41
109
  const idx = parameters.findIndex((parameter) => parameter.name === 'id')
42
110
 
43
111
  if (idx !== -1) {
@@ -47,32 +115,36 @@ export class Query {
47
115
  }
48
116
 
49
117
  if (parameters.length > 0) {
50
- const chunks = parameters
118
+ const criteria = parameters
51
119
  .map(({ name, value }) => `${name}==${value}`)
52
120
  .join(';')
53
121
 
54
- criteria.push(chunks)
122
+ groups.push({ criteria, operator: this.prepend })
55
123
  }
56
124
 
125
+ if (this.query.criteria !== undefined)
126
+ groups.push({ criteria: this.query.criteria, operator: ';' })
127
+
57
128
  if (query.criteria !== undefined)
58
- if (this.closed) throw new http.BadRequest('Query criteria is closed.')
59
- else criteria.push(query.criteria)
60
-
61
- switch (criteria.length) {
62
- case 0:
63
- break
64
- case 1:
65
- query.criteria = criteria[0]
66
- break
67
- default:
68
- query.criteria = '(' + criteria.join(');(') + ')'
69
- break
70
- }
129
+ if (this.closed)
130
+ throw new http.BadRequest('Query criteria is closed')
131
+ else
132
+ groups.push({ criteria: query.criteria, operator: WHATEVER })
133
+
134
+ if (groups.length > 0)
135
+ query.criteria = groups.reduce((acc, { criteria, operator }, i) => {
136
+ return i === groups.length - 1
137
+ ? `${acc}(${criteria})`
138
+ : `${acc}(${criteria})${operator}`
139
+ }, '')
71
140
  }
72
141
 
73
142
  private fitRanges (qs: http.Query): void {
74
143
  const query = qs as core.Query
75
144
 
145
+ assert.ok(this.query.limit !== undefined, 'Query limit must be defined')
146
+ assert.ok(this.query.omit !== undefined, 'Query limit range must be defined')
147
+
76
148
  if (qs.limit !== undefined)
77
149
  query.limit = fit(qs.limit, this.query.limit.range, 'limit')
78
150
  else
@@ -99,7 +171,19 @@ function fit (string: string, range: [number, number], name: string): number {
99
171
 
100
172
  if (number < range[0] || number > range[1])
101
173
  throw new http.BadRequest(`Query ${name} must be between ` +
102
- `${range[0]} and ${range[1]} inclusive.`)
174
+ `${range[0]} and ${range[1]} inclusive`)
103
175
 
104
176
  return number
105
177
  }
178
+
179
+ const WHATEVER = ';'
180
+
181
+ interface CriteriaGroup {
182
+ criteria: string
183
+ operator: ',' | ';'
184
+ }
185
+
186
+ export interface QueryString {
187
+ query: core.Query | null
188
+ parameters: Record<string, string> | null
189
+ }