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

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 (540) hide show
  1. package/components/context.toa.yaml +2 -2
  2. package/components/identity.bans/manifest.toa.yaml +14 -6
  3. package/components/identity.bans/operations/transit.d.ts +14 -0
  4. package/components/identity.bans/operations/transit.js +11 -0
  5. package/components/identity.bans/operations/transit.js.map +1 -0
  6. package/components/identity.bans/operations/tsconfig.tsbuildinfo +1 -0
  7. package/components/identity.bans/source/transit.ts +21 -0
  8. package/components/identity.bans/tsconfig.json +9 -0
  9. package/components/identity.basic/manifest.toa.yaml +19 -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 +8 -6
  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 +11 -9
  24. package/components/identity.basic/source/types.ts +8 -4
  25. package/components/identity.federation/manifest.toa.yaml +58 -19
  26. package/components/identity.federation/operations/authenticate.d.ts +13 -2
  27. package/components/identity.federation/operations/authenticate.js +10 -10
  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/incept.js +14 -0
  31. package/components/identity.federation/operations/incept.js.map +1 -0
  32. package/components/identity.federation/operations/lib/assertions-as-values.js +4 -2
  33. package/components/identity.federation/operations/lib/assertions-as-values.js.map +1 -1
  34. package/components/identity.federation/operations/lib/get.d.ts +1 -0
  35. package/components/identity.federation/operations/lib/get.js +64 -0
  36. package/components/identity.federation/operations/lib/get.js.map +1 -0
  37. package/components/identity.federation/operations/lib/jwt.d.ts +4 -5
  38. package/components/identity.federation/operations/lib/jwt.js +20 -16
  39. package/components/identity.federation/operations/lib/jwt.js.map +1 -1
  40. package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
  41. package/components/identity.federation/operations/types/configuration.d.ts +15 -0
  42. package/components/identity.federation/operations/types/configuration.js +3 -0
  43. package/components/identity.federation/operations/types/configuration.js.map +1 -0
  44. package/components/identity.federation/operations/{types.d.ts → types/context.d.ts} +10 -12
  45. package/{transpiled/directives/vary/embeddings/Embedding.js → components/identity.federation/operations/types/context.js} +1 -1
  46. package/components/identity.federation/operations/types/context.js.map +1 -0
  47. package/components/identity.federation/operations/types/entity.d.ts +6 -0
  48. package/components/identity.federation/operations/types/entity.js +3 -0
  49. package/components/identity.federation/operations/types/entity.js.map +1 -0
  50. package/components/identity.federation/operations/types/index.d.ts +3 -0
  51. package/components/identity.federation/operations/types/index.js +20 -0
  52. package/components/identity.federation/operations/types/index.js.map +1 -0
  53. package/components/identity.federation/source/authenticate.ts +25 -17
  54. package/components/identity.federation/source/incept.ts +26 -0
  55. package/components/identity.federation/source/lib/assertions-as-values.ts +5 -2
  56. package/components/identity.federation/source/lib/get.ts +82 -0
  57. package/components/identity.federation/source/lib/jwt.test.ts +127 -4
  58. package/components/identity.federation/source/lib/jwt.ts +26 -19
  59. package/components/identity.federation/source/types/configuration.ts +16 -0
  60. package/components/identity.federation/source/{types.ts → types/context.ts} +11 -12
  61. package/components/identity.federation/source/types/entity.ts +6 -0
  62. package/components/identity.federation/source/types/index.ts +3 -0
  63. package/components/identity.federation/tsconfig.json +5 -4
  64. package/components/identity.roles/manifest.toa.yaml +9 -8
  65. package/components/identity.roles/operations/grant.d.ts +1 -1
  66. package/components/identity.roles/operations/grant.js +6 -5
  67. package/components/identity.roles/operations/grant.js.map +1 -1
  68. package/components/identity.roles/operations/lib/Entity.d.ts +1 -1
  69. package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
  70. package/components/identity.roles/source/grant.ts +7 -6
  71. package/components/identity.roles/source/lib/Entity.ts +1 -1
  72. package/components/identity.tokens/manifest.toa.yaml +18 -4
  73. package/components/identity.tokens/operations/authenticate.d.ts +2 -2
  74. package/components/identity.tokens/operations/authenticate.js +12 -5
  75. package/components/identity.tokens/operations/authenticate.js.map +1 -1
  76. package/components/identity.tokens/operations/decrypt.js +1 -0
  77. package/components/identity.tokens/operations/decrypt.js.map +1 -1
  78. package/components/identity.tokens/operations/encrypt.js +5 -1
  79. package/components/identity.tokens/operations/encrypt.js.map +1 -1
  80. package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
  81. package/components/identity.tokens/operations/types.d.ts +8 -2
  82. package/components/identity.tokens/receivers/identity.bans.created.js +3 -0
  83. package/components/identity.tokens/source/authenticate.test.ts +11 -4
  84. package/components/identity.tokens/source/authenticate.ts +14 -6
  85. package/components/identity.tokens/source/decrypt.test.ts +5 -3
  86. package/components/identity.tokens/source/decrypt.ts +9 -8
  87. package/components/identity.tokens/source/encrypt.test.ts +26 -2
  88. package/components/identity.tokens/source/encrypt.ts +5 -1
  89. package/components/identity.tokens/source/types.ts +9 -2
  90. package/components/octets.storage/manifest.toa.yaml +10 -11
  91. package/components/octets.storage/operations/get.js +3 -3
  92. package/components/octets.storage/operations/head.js +7 -0
  93. package/components/octets.storage/operations/put.js +132 -0
  94. package/documentation/access.md +71 -29
  95. package/documentation/authorities.md +48 -0
  96. package/documentation/cache.md +8 -1
  97. package/documentation/components.md +48 -15
  98. package/documentation/flow.md +44 -0
  99. package/documentation/identity.md +26 -22
  100. package/documentation/introspection.md +82 -0
  101. package/documentation/map.md +73 -0
  102. package/documentation/octets.md +100 -68
  103. package/documentation/protocol.md +14 -4
  104. package/documentation/query.md +29 -4
  105. package/documentation/require.md +15 -0
  106. package/documentation/tree.md +13 -0
  107. package/features/access.feature +129 -48
  108. package/features/annotation.feature +1 -0
  109. package/features/auth.claims.feature +171 -0
  110. package/features/authorities.basic.feature +141 -0
  111. package/features/authorities.feature +32 -0
  112. package/features/authorities.federation.feature +100 -0
  113. package/features/authorities.tokens.feature +117 -0
  114. package/features/body.feature +2 -0
  115. package/features/cache.feature +109 -5
  116. package/features/cors.feature +7 -1
  117. package/features/debug.feature +34 -0
  118. package/features/directives.feature +3 -0
  119. package/features/dynamic.feature +48 -0
  120. package/features/errors.feature +32 -7
  121. package/features/etag.feature +109 -1
  122. package/features/flow.feature +96 -0
  123. package/features/identity.bans.feature +137 -0
  124. package/features/identity.basic.feature +85 -28
  125. package/features/identity.feature +18 -6
  126. package/features/identity.federation.feature +129 -14
  127. package/features/identity.roles.feature +112 -19
  128. package/features/identity.tokens.feature +54 -4
  129. package/features/introspection.feature +153 -0
  130. package/features/io.feature +38 -1
  131. package/features/map.feature +241 -0
  132. package/features/methods.feature +47 -0
  133. package/features/octets.cloudinary.feature +68 -0
  134. package/features/octets.download.feature +189 -0
  135. package/features/octets.entries.feature +13 -55
  136. package/features/octets.feature +84 -108
  137. package/features/octets.head.feature +40 -0
  138. package/features/octets.meta.feature +65 -15
  139. package/features/octets.workflows.feature +242 -58
  140. package/features/probes.feature +14 -0
  141. package/features/{queries.feature → query.feature} +77 -2
  142. package/features/realtime.feature +34 -0
  143. package/features/require.feature +67 -0
  144. package/features/response.feature +38 -3
  145. package/features/routes.feature +93 -2
  146. package/features/server.feature +21 -0
  147. package/features/steps/.env.example +3 -0
  148. package/features/steps/Database.ts +16 -9
  149. package/features/steps/Gateway.ts +23 -6
  150. package/features/steps/IdP.ts +31 -25
  151. package/features/steps/Parameters.ts +44 -1
  152. package/features/steps/Realtime.ts +151 -0
  153. package/features/steps/components/echo/manifest.toa.yaml +14 -1
  154. package/features/steps/components/echo/operations/identity.js +7 -0
  155. package/features/steps/components/echo/operations/parameters.js +7 -0
  156. package/features/steps/components/echo.beacon/manifest.toa.yaml +2 -0
  157. package/features/steps/components/echo.beacon/operations/hello.js +5 -0
  158. package/features/steps/components/octets.tester/manifest.toa.yaml +22 -2
  159. package/features/steps/components/octets.tester/operations/authority.js +7 -0
  160. package/features/steps/components/octets.tester/operations/bar.js +0 -1
  161. package/features/steps/components/octets.tester/operations/baz.js +0 -2
  162. package/features/steps/components/octets.tester/operations/foo.js +1 -2
  163. package/features/steps/components/octets.tester/operations/redirect.js +12 -0
  164. package/features/steps/components/octets.tester/operations/yex.js +16 -0
  165. package/features/steps/components/octets.tester/operations/yield.js +13 -0
  166. package/features/steps/components/pots/manifest.toa.yaml +14 -3
  167. package/features/steps/components/users/manifest.toa.yaml +0 -1
  168. package/features/steps/components/users.properties/manifest.toa.yaml +1 -1
  169. package/features/streams.feature +5 -0
  170. package/features/timing.feature +4 -1
  171. package/package.json +21 -12
  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 +2 -0
  176. package/schemas/octets/put.cos.yaml +25 -0
  177. package/schemas/query.cos.yaml +4 -10
  178. package/source/Annotation.ts +3 -3
  179. package/source/Branch.ts +1 -0
  180. package/source/Composition.ts +0 -6
  181. package/source/Context.ts +1 -0
  182. package/source/Directive.test.ts +1 -1
  183. package/source/Directive.ts +7 -6
  184. package/source/Endpoint.ts +59 -17
  185. package/source/Factory.ts +22 -13
  186. package/source/Gateway.ts +67 -18
  187. package/source/HTTP/Context.ts +26 -3
  188. package/source/HTTP/Server.ts +61 -47
  189. package/source/HTTP/exceptions.ts +13 -1
  190. package/source/HTTP/formats/index.ts +3 -3
  191. package/source/HTTP/messages.test.ts +45 -2
  192. package/source/HTTP/messages.ts +32 -8
  193. package/source/Introspection.ts +11 -0
  194. package/source/Mapping.ts +68 -21
  195. package/source/Query.test.ts +3 -3
  196. package/source/Query.ts +123 -33
  197. package/source/RTD/Context.ts +1 -1
  198. package/source/RTD/Endpoint.ts +3 -0
  199. package/source/RTD/Method.ts +16 -0
  200. package/source/RTD/Node.ts +29 -13
  201. package/source/RTD/Route.ts +5 -4
  202. package/source/RTD/Tree.ts +2 -2
  203. package/source/RTD/factory.ts +5 -2
  204. package/source/RTD/syntax/parse.test.ts +1 -1
  205. package/source/RTD/syntax/parse.ts +37 -24
  206. package/source/RTD/syntax/types.ts +6 -4
  207. package/source/Remotes.ts +7 -6
  208. package/source/Tenant.ts +6 -20
  209. package/source/deployment.ts +33 -23
  210. package/source/directives/auth/Anyone.ts +13 -0
  211. package/source/directives/auth/Authorization.ts +44 -21
  212. package/source/directives/auth/Delegate.ts +14 -4
  213. package/source/directives/auth/Echo.ts +19 -5
  214. package/source/directives/auth/Federation.ts +84 -0
  215. package/source/directives/auth/Incept.ts +4 -3
  216. package/source/directives/auth/Role.test.ts +53 -6
  217. package/source/directives/auth/Role.ts +22 -14
  218. package/source/directives/auth/Scheme.ts +1 -1
  219. package/source/directives/auth/split.ts +1 -1
  220. package/source/directives/auth/types.ts +2 -2
  221. package/source/directives/cache/Cache.ts +13 -6
  222. package/source/directives/cache/Control.ts +42 -16
  223. package/source/directives/cors/CORS.ts +2 -1
  224. package/source/directives/dev/Development.ts +1 -1
  225. package/source/directives/flow/Compose.ts +68 -0
  226. package/source/directives/flow/Fetch.ts +86 -0
  227. package/source/directives/flow/Flow.ts +42 -0
  228. package/source/directives/flow/index.ts +3 -0
  229. package/source/directives/flow/types.ts +7 -0
  230. package/source/directives/index.ts +4 -2
  231. package/source/directives/io/IO.ts +1 -1
  232. package/source/directives/io/Input.ts +4 -4
  233. package/source/directives/io/Output.ts +5 -4
  234. package/source/directives/map/Authority.ts +15 -0
  235. package/source/directives/map/Claims.ts +37 -0
  236. package/source/directives/map/Directive.ts +4 -0
  237. package/source/directives/map/Headers.ts +38 -0
  238. package/source/directives/map/Language.ts +42 -0
  239. package/source/directives/map/Languages.ts +11 -0
  240. package/source/directives/map/Map.ts +56 -0
  241. package/source/directives/map/Mapping.ts +13 -0
  242. package/source/directives/{vary → map}/Properties.ts +2 -4
  243. package/source/directives/map/Segments.ts +26 -0
  244. package/source/directives/map/index.ts +3 -0
  245. package/source/directives/octets/Context.ts +3 -2
  246. package/source/directives/octets/Delete.ts +11 -11
  247. package/source/directives/octets/Get.ts +86 -0
  248. package/source/directives/octets/Octets.ts +9 -12
  249. package/source/directives/octets/{Store.ts → Put.ts} +37 -21
  250. package/source/directives/octets/Workflow.ts +1 -1
  251. package/source/directives/octets/bytes.test.ts +30 -0
  252. package/source/directives/octets/bytes.ts +18 -0
  253. package/source/directives/octets/schemas.ts +4 -8
  254. package/source/directives/octets/workflows/Execution.ts +60 -8
  255. package/source/directives/octets/workflows/Workflow.ts +4 -4
  256. package/source/directives/require/Directive.ts +5 -0
  257. package/source/directives/require/Headers.ts +20 -0
  258. package/source/directives/require/Require.ts +28 -0
  259. package/source/directives/require/index.ts +3 -0
  260. package/source/exceptions.ts +14 -6
  261. package/source/manifest.ts +10 -11
  262. package/source/root.ts +5 -5
  263. package/source/schemas.ts +1 -1
  264. package/transpiled/Annotation.d.ts +3 -3
  265. package/transpiled/Branch.d.ts +1 -0
  266. package/transpiled/Composition.d.ts +0 -1
  267. package/transpiled/Composition.js +0 -4
  268. package/transpiled/Composition.js.map +1 -1
  269. package/transpiled/Context.d.ts +1 -0
  270. package/transpiled/Directive.js +7 -5
  271. package/transpiled/Directive.js.map +1 -1
  272. package/transpiled/Endpoint.d.ts +6 -4
  273. package/transpiled/Endpoint.js +39 -9
  274. package/transpiled/Endpoint.js.map +1 -1
  275. package/transpiled/Factory.d.ts +3 -2
  276. package/transpiled/Factory.js +18 -10
  277. package/transpiled/Factory.js.map +1 -1
  278. package/transpiled/Gateway.d.ts +3 -0
  279. package/transpiled/Gateway.js +50 -10
  280. package/transpiled/Gateway.js.map +1 -1
  281. package/transpiled/HTTP/Context.d.ts +9 -2
  282. package/transpiled/HTTP/Context.js +16 -2
  283. package/transpiled/HTTP/Context.js.map +1 -1
  284. package/transpiled/HTTP/Server.d.ts +13 -2
  285. package/transpiled/HTTP/Server.js +47 -40
  286. package/transpiled/HTTP/Server.js.map +1 -1
  287. package/transpiled/HTTP/exceptions.d.ts +7 -1
  288. package/transpiled/HTTP/exceptions.js +13 -1
  289. package/transpiled/HTTP/exceptions.js.map +1 -1
  290. package/transpiled/HTTP/formats/index.js +3 -3
  291. package/transpiled/HTTP/formats/index.js.map +1 -1
  292. package/transpiled/HTTP/messages.d.ts +2 -1
  293. package/transpiled/HTTP/messages.js +30 -7
  294. package/transpiled/HTTP/messages.js.map +1 -1
  295. package/transpiled/Introspection.d.ts +9 -0
  296. package/transpiled/Introspection.js +3 -0
  297. package/transpiled/Introspection.js.map +1 -0
  298. package/transpiled/Mapping.d.ts +11 -2
  299. package/transpiled/Mapping.js +50 -19
  300. package/transpiled/Mapping.js.map +1 -1
  301. package/transpiled/Query.d.ts +10 -1
  302. package/transpiled/Query.js +87 -30
  303. package/transpiled/Query.js.map +1 -1
  304. package/transpiled/RTD/Context.d.ts +1 -1
  305. package/transpiled/RTD/Endpoint.d.ts +1 -0
  306. package/transpiled/RTD/Method.d.ts +4 -0
  307. package/transpiled/RTD/Method.js +11 -0
  308. package/transpiled/RTD/Method.js.map +1 -1
  309. package/transpiled/RTD/Node.d.ts +4 -1
  310. package/transpiled/RTD/Node.js +23 -12
  311. package/transpiled/RTD/Node.js.map +1 -1
  312. package/transpiled/RTD/Route.d.ts +1 -1
  313. package/transpiled/RTD/Route.js +0 -1
  314. package/transpiled/RTD/Route.js.map +1 -1
  315. package/transpiled/RTD/Tree.d.ts +1 -1
  316. package/transpiled/RTD/Tree.js.map +1 -1
  317. package/transpiled/RTD/factory.js +5 -2
  318. package/transpiled/RTD/factory.js.map +1 -1
  319. package/transpiled/RTD/syntax/parse.js +34 -22
  320. package/transpiled/RTD/syntax/parse.js.map +1 -1
  321. package/transpiled/RTD/syntax/types.d.ts +5 -3
  322. package/transpiled/RTD/syntax/types.js +1 -1
  323. package/transpiled/RTD/syntax/types.js.map +1 -1
  324. package/transpiled/Remotes.d.ts +4 -4
  325. package/transpiled/Remotes.js +6 -5
  326. package/transpiled/Remotes.js.map +1 -1
  327. package/transpiled/Tenant.d.ts +5 -5
  328. package/transpiled/Tenant.js +2 -13
  329. package/transpiled/Tenant.js.map +1 -1
  330. package/transpiled/deployment.d.ts +1 -1
  331. package/transpiled/deployment.js +28 -20
  332. package/transpiled/deployment.js.map +1 -1
  333. package/transpiled/directives/auth/Anyone.d.ts +6 -0
  334. package/transpiled/directives/auth/Anyone.js +14 -0
  335. package/transpiled/directives/auth/Anyone.js.map +1 -0
  336. package/transpiled/directives/auth/Authorization.d.ts +1 -1
  337. package/transpiled/directives/auth/Authorization.js +32 -18
  338. package/transpiled/directives/auth/Authorization.js.map +1 -1
  339. package/transpiled/directives/auth/Delegate.d.ts +4 -2
  340. package/transpiled/directives/auth/Delegate.js +11 -4
  341. package/transpiled/directives/auth/Delegate.js.map +1 -1
  342. package/transpiled/directives/auth/Echo.d.ts +4 -3
  343. package/transpiled/directives/auth/Echo.js +13 -3
  344. package/transpiled/directives/auth/Echo.js.map +1 -1
  345. package/transpiled/directives/auth/Federation.d.ts +16 -0
  346. package/transpiled/directives/auth/Federation.js +57 -0
  347. package/transpiled/directives/auth/Federation.js.map +1 -0
  348. package/transpiled/directives/auth/Incept.js +4 -3
  349. package/transpiled/directives/auth/Incept.js.map +1 -1
  350. package/transpiled/directives/auth/Role.d.ts +4 -1
  351. package/transpiled/directives/auth/Role.js +20 -14
  352. package/transpiled/directives/auth/Role.js.map +1 -1
  353. package/transpiled/directives/auth/Scheme.js +1 -1
  354. package/transpiled/directives/auth/Scheme.js.map +1 -1
  355. package/transpiled/directives/auth/split.js +1 -1
  356. package/transpiled/directives/auth/split.js.map +1 -1
  357. package/transpiled/directives/auth/types.d.ts +1 -1
  358. package/transpiled/directives/cache/Cache.d.ts +3 -3
  359. package/transpiled/directives/cache/Cache.js +10 -4
  360. package/transpiled/directives/cache/Cache.js.map +1 -1
  361. package/transpiled/directives/cache/Control.d.ts +2 -1
  362. package/transpiled/directives/cache/Control.js +29 -12
  363. package/transpiled/directives/cache/Control.js.map +1 -1
  364. package/transpiled/directives/cors/CORS.js +2 -1
  365. package/transpiled/directives/cors/CORS.js.map +1 -1
  366. package/transpiled/directives/dev/Development.js +1 -1
  367. package/transpiled/directives/dev/Development.js.map +1 -1
  368. package/transpiled/directives/flow/Compose.d.ts +8 -0
  369. package/transpiled/directives/flow/Compose.js +74 -0
  370. package/transpiled/directives/flow/Compose.js.map +1 -0
  371. package/transpiled/directives/flow/Fetch.d.ts +12 -0
  372. package/transpiled/directives/flow/Fetch.js +58 -0
  373. package/transpiled/directives/flow/Fetch.js.map +1 -0
  374. package/transpiled/directives/flow/Flow.d.ts +10 -0
  375. package/transpiled/directives/flow/Flow.js +33 -0
  376. package/transpiled/directives/flow/Flow.js.map +1 -0
  377. package/transpiled/directives/flow/index.d.ts +2 -0
  378. package/transpiled/directives/flow/index.js +6 -0
  379. package/transpiled/directives/flow/index.js.map +1 -0
  380. package/transpiled/directives/flow/types.d.ts +6 -0
  381. package/transpiled/directives/flow/types.js.map +1 -0
  382. package/transpiled/directives/index.js +4 -2
  383. package/transpiled/directives/index.js.map +1 -1
  384. package/transpiled/directives/io/IO.js +1 -1
  385. package/transpiled/directives/io/IO.js.map +1 -1
  386. package/transpiled/directives/io/Input.js +2 -2
  387. package/transpiled/directives/io/Input.js.map +1 -1
  388. package/transpiled/directives/io/Output.js +2 -2
  389. package/transpiled/directives/io/Output.js.map +1 -1
  390. package/transpiled/directives/map/Authority.d.ts +6 -0
  391. package/transpiled/directives/map/Authority.js +19 -0
  392. package/transpiled/directives/map/Authority.js.map +1 -0
  393. package/transpiled/directives/map/Claims.d.ts +6 -0
  394. package/transpiled/directives/map/Claims.js +29 -0
  395. package/transpiled/directives/map/Claims.js.map +1 -0
  396. package/transpiled/directives/map/Directive.d.ts +3 -0
  397. package/transpiled/directives/map/Directive.js.map +1 -0
  398. package/transpiled/directives/map/Headers.d.ts +7 -0
  399. package/transpiled/directives/map/Headers.js +34 -0
  400. package/transpiled/directives/map/Headers.js.map +1 -0
  401. package/transpiled/directives/map/Language.d.ts +10 -0
  402. package/transpiled/directives/map/Language.js +38 -0
  403. package/transpiled/directives/map/Language.js.map +1 -0
  404. package/transpiled/directives/map/Languages.d.ts +4 -0
  405. package/transpiled/directives/map/Languages.js +17 -0
  406. package/transpiled/directives/map/Languages.js.map +1 -0
  407. package/transpiled/directives/map/Map.d.ts +11 -0
  408. package/transpiled/directives/map/Map.js +44 -0
  409. package/transpiled/directives/map/Map.js.map +1 -0
  410. package/transpiled/directives/map/Mapping.d.ts +8 -0
  411. package/transpiled/directives/map/Mapping.js +11 -0
  412. package/transpiled/directives/map/Mapping.js.map +1 -0
  413. package/transpiled/directives/{vary → map}/Properties.d.ts +2 -2
  414. package/transpiled/directives/{vary → map}/Properties.js +1 -3
  415. package/transpiled/directives/map/Properties.js.map +1 -0
  416. package/transpiled/directives/map/Segments.d.ts +6 -0
  417. package/transpiled/directives/map/Segments.js +25 -0
  418. package/transpiled/directives/map/Segments.js.map +1 -0
  419. package/transpiled/directives/map/index.d.ts +2 -0
  420. package/transpiled/directives/map/index.js +6 -0
  421. package/transpiled/directives/map/index.js.map +1 -0
  422. package/transpiled/directives/octets/Context.js +4 -24
  423. package/transpiled/directives/octets/Context.js.map +1 -1
  424. package/transpiled/directives/octets/Delete.js +8 -8
  425. package/transpiled/directives/octets/Delete.js.map +1 -1
  426. package/transpiled/directives/octets/{Fetch.d.ts → Get.d.ts} +5 -6
  427. package/transpiled/directives/octets/{Fetch.js → Get.js} +25 -29
  428. package/transpiled/directives/octets/Get.js.map +1 -0
  429. package/transpiled/directives/octets/Octets.js +9 -12
  430. package/transpiled/directives/octets/Octets.js.map +1 -1
  431. package/transpiled/directives/octets/{Store.d.ts → Put.d.ts} +7 -2
  432. package/transpiled/directives/octets/{Store.js → Put.js} +26 -19
  433. package/transpiled/directives/octets/Put.js.map +1 -0
  434. package/transpiled/directives/octets/Workflow.js +1 -1
  435. package/transpiled/directives/octets/Workflow.js.map +1 -1
  436. package/transpiled/directives/octets/bytes.d.ts +1 -0
  437. package/transpiled/directives/octets/bytes.js +21 -0
  438. package/transpiled/directives/octets/bytes.js.map +1 -0
  439. package/transpiled/directives/octets/schemas.d.ts +4 -8
  440. package/transpiled/directives/octets/schemas.js +3 -6
  441. package/transpiled/directives/octets/schemas.js.map +1 -1
  442. package/transpiled/directives/octets/workflows/Execution.d.ts +5 -1
  443. package/transpiled/directives/octets/workflows/Execution.js +44 -9
  444. package/transpiled/directives/octets/workflows/Execution.js.map +1 -1
  445. package/transpiled/directives/octets/workflows/Workflow.d.ts +1 -1
  446. package/transpiled/directives/octets/workflows/Workflow.js +2 -1
  447. package/transpiled/directives/octets/workflows/Workflow.js.map +1 -1
  448. package/transpiled/directives/require/Directive.d.ts +4 -0
  449. package/transpiled/directives/require/Directive.js +3 -0
  450. package/transpiled/directives/require/Directive.js.map +1 -0
  451. package/transpiled/directives/require/Headers.d.ts +7 -0
  452. package/transpiled/directives/require/Headers.js +19 -0
  453. package/transpiled/directives/require/Headers.js.map +1 -0
  454. package/transpiled/directives/require/Require.d.ts +9 -0
  455. package/transpiled/directives/require/Require.js +27 -0
  456. package/transpiled/directives/require/Require.js.map +1 -0
  457. package/transpiled/directives/require/index.d.ts +2 -0
  458. package/transpiled/directives/require/index.js +6 -0
  459. package/transpiled/directives/require/index.js.map +1 -0
  460. package/transpiled/exceptions.d.ts +3 -2
  461. package/transpiled/exceptions.js +8 -1
  462. package/transpiled/exceptions.js.map +1 -1
  463. package/transpiled/manifest.js +10 -11
  464. package/transpiled/manifest.js.map +1 -1
  465. package/transpiled/root.js +5 -5
  466. package/transpiled/root.js.map +1 -1
  467. package/transpiled/schemas.d.ts +1 -1
  468. package/transpiled/schemas.js +2 -2
  469. package/transpiled/schemas.js.map +1 -1
  470. package/transpiled/tsconfig.tsbuildinfo +1 -1
  471. package/components/identity.basic/operations/create.d.ts +0 -10
  472. package/components/identity.basic/operations/create.js +0 -10
  473. package/components/identity.basic/operations/create.js.map +0 -1
  474. package/components/identity.basic/source/create.ts +0 -18
  475. package/components/identity.federation/operations/create.d.ts +0 -10
  476. package/components/identity.federation/operations/create.js +0 -15
  477. package/components/identity.federation/operations/create.js.map +0 -1
  478. package/components/identity.federation/operations/schemas.d.ts +0 -59
  479. package/components/identity.federation/operations/schemas.js +0 -9
  480. package/components/identity.federation/operations/schemas.js.map +0 -1
  481. package/components/identity.federation/operations/types.js.map +0 -1
  482. package/components/identity.federation/source/create.ts +0 -26
  483. package/components/identity.federation/source/schemas.ts +0 -61
  484. package/components/octets.storage/operations/fetch.js +0 -46
  485. package/components/octets.storage/operations/list.js +0 -7
  486. package/components/octets.storage/operations/permute.js +0 -7
  487. package/components/octets.storage/operations/store.js +0 -11
  488. package/documentation/vary.md +0 -69
  489. package/features/steps/components/octets.tester/operations/diversify.js +0 -14
  490. package/features/vary.feature +0 -180
  491. package/schemas/octets/context.cos.yaml +0 -1
  492. package/schemas/octets/fetch.cos.yaml +0 -3
  493. package/schemas/octets/permute.cos.yaml +0 -1
  494. package/schemas/octets/store.cos.yaml +0 -3
  495. package/source/HTTP/Server.test.ts +0 -126
  496. package/source/directives/octets/Fetch.ts +0 -100
  497. package/source/directives/octets/List.ts +0 -72
  498. package/source/directives/octets/Permute.ts +0 -44
  499. package/source/directives/vary/Directive.ts +0 -6
  500. package/source/directives/vary/Embed.ts +0 -62
  501. package/source/directives/vary/Vary.ts +0 -48
  502. package/source/directives/vary/embeddings/Embedding.ts +0 -6
  503. package/source/directives/vary/embeddings/Header.ts +0 -32
  504. package/source/directives/vary/embeddings/Language.ts +0 -31
  505. package/source/directives/vary/embeddings/index.ts +0 -11
  506. package/source/directives/vary/index.ts +0 -3
  507. package/transpiled/directives/octets/Fetch.js.map +0 -1
  508. package/transpiled/directives/octets/List.d.ts +0 -16
  509. package/transpiled/directives/octets/List.js +0 -74
  510. package/transpiled/directives/octets/List.js.map +0 -1
  511. package/transpiled/directives/octets/Permute.d.ts +0 -11
  512. package/transpiled/directives/octets/Permute.js +0 -58
  513. package/transpiled/directives/octets/Permute.js.map +0 -1
  514. package/transpiled/directives/octets/Store.js.map +0 -1
  515. package/transpiled/directives/vary/Directive.d.ts +0 -5
  516. package/transpiled/directives/vary/Directive.js.map +0 -1
  517. package/transpiled/directives/vary/Embed.d.ts +0 -10
  518. package/transpiled/directives/vary/Embed.js +0 -49
  519. package/transpiled/directives/vary/Embed.js.map +0 -1
  520. package/transpiled/directives/vary/Properties.js.map +0 -1
  521. package/transpiled/directives/vary/Vary.d.ts +0 -10
  522. package/transpiled/directives/vary/Vary.js +0 -36
  523. package/transpiled/directives/vary/Vary.js.map +0 -1
  524. package/transpiled/directives/vary/embeddings/Embedding.d.ts +0 -5
  525. package/transpiled/directives/vary/embeddings/Embedding.js.map +0 -1
  526. package/transpiled/directives/vary/embeddings/Header.d.ts +0 -7
  527. package/transpiled/directives/vary/embeddings/Header.js +0 -28
  528. package/transpiled/directives/vary/embeddings/Header.js.map +0 -1
  529. package/transpiled/directives/vary/embeddings/Language.d.ts +0 -7
  530. package/transpiled/directives/vary/embeddings/Language.js +0 -28
  531. package/transpiled/directives/vary/embeddings/Language.js.map +0 -1
  532. package/transpiled/directives/vary/embeddings/index.d.ts +0 -5
  533. package/transpiled/directives/vary/embeddings/index.js +0 -10
  534. package/transpiled/directives/vary/embeddings/index.js.map +0 -1
  535. package/transpiled/directives/vary/index.d.ts +0 -2
  536. package/transpiled/directives/vary/index.js +0 -6
  537. package/transpiled/directives/vary/index.js.map +0 -1
  538. /package/schemas/octets/{list.cos.yaml → get.cos.yaml} +0 -0
  539. /package/{components/identity.federation/operations → transpiled/directives/flow}/types.js +0 -0
  540. /package/transpiled/directives/{vary → map}/Directive.js +0 -0
package/source/Context.ts CHANGED
@@ -5,4 +5,5 @@ export type Context = RTD.Context<Extension>
5
5
  interface Extension {
6
6
  namespace: string
7
7
  component: string
8
+ version: string
8
9
  }
@@ -65,7 +65,7 @@ it('should throw error if directive family is not found', async () => {
65
65
  }
66
66
 
67
67
  expect(() => factory.create([declaration]))
68
- .toThrowError(`Directive family '${declaration.family}' is not found.`)
68
+ .toThrowError(`Directive family '${declaration.family}' is not found`)
69
69
  })
70
70
 
71
71
  it('should apply directive', async () => {
@@ -17,11 +17,8 @@ export class Directives implements RTD.Directives {
17
17
 
18
18
  const output = await set.family.preflight(set.directives, context, parameters)
19
19
 
20
- if (output !== null) {
21
- await this.settle(context, output)
22
-
20
+ if (output !== null)
23
21
  return output
24
- }
25
22
  }
26
23
 
27
24
  return null
@@ -61,7 +58,7 @@ export class DirectivesFactory implements RTD.DirectiveFactory {
61
58
  const family = this.families[declaration.family]
62
59
 
63
60
  if (family === undefined)
64
- throw new Error(`Directive family '${declaration.family}' is not found.`)
61
+ throw new Error(`Directive family '${declaration.family}' is not found`)
65
62
 
66
63
  const directive = family.create(declaration.name, declaration.value, this.remotes)
67
64
 
@@ -90,8 +87,12 @@ export class DirectivesFactory implements RTD.DirectiveFactory {
90
87
 
91
88
  export const shortcuts: RTD.syntax.Shortcuts = new Map([
92
89
  ['anonymous', 'auth:anonymous'],
90
+ ['anyone', 'auth:anyone'],
93
91
  ['id', 'auth:id'],
94
92
  ['role', 'auth:role'],
95
93
  ['rule', 'auth:rule'],
96
- ['incept', 'auth:incept']
94
+ ['incept', 'auth:incept'],
95
+ ['input', 'io:input'],
96
+ ['output', 'io:output'],
97
+ ['languages', 'map:languages']
97
98
  ])
@@ -1,34 +1,41 @@
1
- import { type Component } from '@toa.io/core'
2
- import { type Remotes } from './Remotes'
1
+ import { console } from 'openspan'
3
2
  import { Mapping } from './Mapping'
4
- import { type Context } from './Context'
5
3
  import * as http from './HTTP'
4
+ import type { Introspection, Schema } from './Introspection'
5
+ import type { Remote } from '@toa.io/core'
6
+ import type { Remotes } from './Remotes'
7
+ import type { Context } from './Context'
6
8
  import type * as RTD from './RTD'
7
9
 
8
10
  export class Endpoint implements RTD.Endpoint {
9
11
  private readonly endpoint: string
10
12
  private readonly mapping: Mapping
11
- private readonly discovery: Promise<Component>
12
- private remote: Component | null = null
13
+ private readonly discovery: Promise<Remote>
14
+ private remote: Remote | null = null
13
15
 
14
- public constructor (endpoint: string, mapping: Mapping, discovery: Promise<Component>) {
16
+ public constructor (endpoint: string, mapping: Mapping, discovery: Promise<Remote>) {
15
17
  this.endpoint = endpoint
16
18
  this.mapping = mapping
17
19
  this.discovery = discovery
18
20
  }
19
21
 
20
- public async call
21
- (context: http.Context, parameters: RTD.Parameter[]): Promise<http.OutgoingMessage> {
22
+ public async call (context: http.Context, parameters: RTD.Parameter[]): Promise<http.OutgoingMessage> {
22
23
  const body = await context.body()
23
24
  const query = this.query(context)
24
25
  const request = this.mapping.fit(body, query, parameters)
25
26
 
26
27
  this.remote ??= await this.discovery
27
28
 
29
+ if (context.debug)
30
+ console.debug('Calling operation', {
31
+ endpoint: this.remote.locator.id + '.' + this.endpoint,
32
+ request
33
+ })
34
+
28
35
  const reply = await this.remote.invoke(this.endpoint, request)
29
36
 
30
37
  if (reply instanceof Error)
31
- throw new http.Conflict(reply)
38
+ throw new http.UnprocessableEntity(reply)
32
39
 
33
40
  const message: http.OutgoingMessage = {}
34
41
 
@@ -51,6 +58,41 @@ export class Endpoint implements RTD.Endpoint {
51
58
  return message
52
59
  }
53
60
 
61
+ public async explain (parameters: RTD.Parameter[]): Promise<Introspection> {
62
+ this.remote ??= await this.discovery
63
+
64
+ // eslint-disable-next-line @typescript-eslint/await-thenable
65
+ const operation = await this.remote.explain(this.endpoint)
66
+
67
+ let route: Record<string, Schema> | null = null
68
+
69
+ if (operation.input?.type === 'object')
70
+ for (const parameter of parameters) {
71
+ const schema = operation.input.properties[parameter.name]
72
+
73
+ // eslint-disable-next-line max-depth
74
+ if (schema !== undefined) {
75
+ route ??= {}
76
+ route[parameter.name] = schema
77
+
78
+ delete operation.input.properties[parameter.name]
79
+ }
80
+ }
81
+
82
+ const query = this.mapping.explain(operation)
83
+ const introspection: Introspection = {}
84
+
85
+ if (route !== null)
86
+ introspection.route = route
87
+
88
+ if (query !== null)
89
+ introspection.query = query
90
+
91
+ Object.assign(introspection, operation)
92
+
93
+ return introspection
94
+ }
95
+
54
96
  public async close (): Promise<void> {
55
97
  this.remote ??= await this.discovery
56
98
 
@@ -61,7 +103,7 @@ export class Endpoint implements RTD.Endpoint {
61
103
  const query: http.Query = Object.fromEntries(context.url.searchParams)
62
104
  const etag = context.request.headers['if-match']
63
105
 
64
- if (etag !== undefined)
106
+ if (etag !== undefined && this.mapping.queryable)
65
107
  query.version = this.version(etag)
66
108
 
67
109
  return query
@@ -71,7 +113,7 @@ export class Endpoint implements RTD.Endpoint {
71
113
  const match = etag.match(ETAG)
72
114
 
73
115
  if (match === null)
74
- throw new http.BadRequest('Invalid ETag.')
116
+ throw new http.BadRequest('Invalid ETag')
75
117
 
76
118
  return Number.parseInt(match.groups!.version)
77
119
  }
@@ -86,21 +128,21 @@ export class EndpointsFactory implements RTD.EndpointsFactory {
86
128
 
87
129
  public create (method: RTD.syntax.Method, context: Context): Endpoint {
88
130
  if (method.mapping === undefined)
89
- throw new Error('Cannot create Endpoint without mapping.')
131
+ throw new Error('Cannot create Endpoint without mapping')
90
132
 
91
133
  const mapping = Mapping.create(method.mapping.query)
92
- const namespace = method.mapping.namespace ?? context.extension?.namespace
93
- const component = method.mapping.component ?? context.extension?.component
134
+ const namespace = method.mapping.namespace ?? context.extension.namespace
135
+ const component = method.mapping.component ?? context.extension.component
94
136
 
95
137
  if (namespace === undefined || component === undefined)
96
- throw new Error('Annotation endpoints must be fully qualified.')
138
+ throw new Error('Annotation endpoints must be fully qualified')
97
139
 
98
- const discovery = this.remotes.discover(namespace, component)
140
+ const discovery = this.remotes.discover(namespace, component, context.extension.version)
99
141
 
100
142
  return new Endpoint(method.mapping.endpoint, mapping, discovery)
101
143
  }
102
144
  }
103
145
 
104
- const ETAG = /^"(?<version>\d{1,32})"$/
146
+ const ETAG = /^(W\/)?"(?<version>\d{1,32})"$/
105
147
 
106
148
  const INTERRUPT = true
package/source/Factory.ts CHANGED
@@ -1,14 +1,19 @@
1
+ import assert from 'node:assert'
2
+ import { decode } from '@toa.io/generic'
1
3
  import { Tenant } from './Tenant'
2
4
  import { Gateway } from './Gateway'
3
5
  import { Remotes } from './Remotes'
4
- import { Tree, syntax } from './RTD'
5
- import { Server } from './HTTP'
6
+ import { Tree } from './RTD'
6
7
  import { EndpointsFactory } from './Endpoint'
7
8
  import { families, interceptors } from './directives'
8
9
  import { DirectivesFactory } from './Directive'
9
10
  import { Composition } from './Composition'
10
11
  import * as root from './root'
11
12
  import { Interception } from './Interception'
13
+ import * as http from './HTTP'
14
+ import type { Manifest } from '@toa.io/norm'
15
+ import type { Branch } from './Branch'
16
+ import type { syntax } from './RTD'
12
17
  import type { Broadcast } from './Gateway'
13
18
  import type { Connector, Locator, extensions } from '@toa.io/core'
14
19
 
@@ -19,23 +24,27 @@ export class Factory implements extensions.Factory {
19
24
  this.boot = boot
20
25
  }
21
26
 
22
- public tenant (locator: Locator, node: syntax.Node): Connector {
27
+ public tenant (locator: Locator, node: syntax.Node, manifest: Manifest): Connector {
23
28
  const broadcast: Broadcast = this.boot.bindings.broadcast(CHANNEL, locator.id)
24
29
 
25
- return new Tenant(broadcast, locator, node)
30
+ const branch: Branch = {
31
+ namespace: locator.namespace,
32
+ component: locator.name,
33
+ isolated: locator.namespace === 'identity',
34
+ node,
35
+ version: manifest.version
36
+ }
37
+
38
+ return new Tenant(broadcast, branch)
26
39
  }
27
40
 
28
41
  public service (): Connector | null {
29
- const debug = process.env.TOA_EXPOSITION_DEBUG === '1'
30
- const trace = process.env.TOA_EXPOSITION_TRACE === '1'
31
- const broadcast: Broadcast = this.boot.bindings.broadcast(CHANNEL)
32
-
33
- const server = Server.create({
34
- methods: syntax.verbs,
35
- debug,
36
- trace
37
- })
42
+ assert.ok(process.env.TOA_EXPOSITION_PROPERTIES,
43
+ 'TOA_EXPOSITION_PROPERTIES is undefined')
38
44
 
45
+ const options = decode<http.Options>(process.env.TOA_EXPOSITION_PROPERTIES)
46
+ const broadcast: Broadcast = this.boot.bindings.broadcast(CHANNEL)
47
+ const server = http.Server.create({ ...options })
39
48
  const remotes = new Remotes(this.boot)
40
49
  const node = root.resolve()
41
50
  const methods = new EndpointsFactory(remotes)
package/source/Gateway.ts CHANGED
@@ -1,8 +1,10 @@
1
+ import assert from 'node:assert'
2
+ import { console } from 'openspan'
1
3
  import { type bindings, Connector } from '@toa.io/core'
2
4
  import * as http from './HTTP'
3
5
  import { rethrow } from './exceptions'
4
6
  import type { Interception } from './Interception'
5
- import type { Method, Parameter, Tree } from './RTD'
7
+ import type { Node, Method, Parameter, Tree, Match } from './RTD'
6
8
  import type { Label } from './discovery'
7
9
  import type { Branch } from './Branch'
8
10
 
@@ -10,6 +12,7 @@ export class Gateway extends Connector {
10
12
  private readonly broadcast: Broadcast
11
13
  private readonly tree: Tree
12
14
  private readonly interceptor: Interception
15
+ private readonly merged = new Set<string>()
13
16
 
14
17
  public constructor (broadcast: Broadcast, tree: Tree, interception: Interception) {
15
18
  super()
@@ -28,15 +31,10 @@ export class Gateway extends Connector {
28
31
  if (interception !== null)
29
32
  return interception
30
33
 
31
- const match = this.tree.match(context.url.pathname)
32
-
33
- if (match === null)
34
- throw new http.NotFound()
34
+ const { node, parameters } = this.match(context)
35
35
 
36
- const {
37
- node,
38
- parameters
39
- } = match
36
+ if (context.request.method === 'OPTIONS')
37
+ return await this.explain(node, parameters)
40
38
 
41
39
  if (!(context.request.method in node.methods))
42
40
  throw new http.MethodNotAllowed()
@@ -58,17 +56,41 @@ export class Gateway extends Connector {
58
56
  protected override async open (): Promise<void> {
59
57
  await this.discover()
60
58
 
61
- console.info('Gateway has started and is awaiting resource branches.')
59
+ console.info('Gateway started')
62
60
  }
63
61
 
64
62
  protected override dispose (): void {
65
- console.info('Gateway is closed.')
63
+ console.info('Gateway is closed')
66
64
  }
67
65
 
68
- private async call (method: Method, context: http.Context, parameters: Parameter[]):
69
- Promise<http.OutgoingMessage> {
66
+ private match (context: http.Context): Match {
67
+ const match = this.tree.match(context.url.pathname)
68
+
69
+ if (match === null)
70
+ throw new http.NotFound('Route not found')
71
+
72
+ if (match.node.forward === null)
73
+ return match
74
+
75
+ const destination = match.node.forward.replace(/\/:([^/]+)/g,
76
+ (_, name) => {
77
+ const value = match.parameters.find((parameter) => parameter.name === name)?.value
78
+
79
+ assert.ok(value !== undefined, `Forwarded parameter '${name}' not found`)
80
+
81
+ return `/${value}`
82
+ })
83
+
84
+ const forward = this.tree.match(destination)
85
+
86
+ assert.ok(forward !== null, 'Forwarded route not found')
87
+
88
+ return forward
89
+ }
90
+
91
+ private async call (method: Method, context: http.Context, parameters: Parameter[]): Promise<http.OutgoingMessage> {
70
92
  if (context.url.pathname[context.url.pathname.length - 1] !== '/')
71
- throw new http.NotFound('Trailing slash is required.')
93
+ throw new http.NotFound('Trailing slash is required')
72
94
 
73
95
  if (context.encoder === null)
74
96
  throw new http.NotAcceptable()
@@ -81,19 +103,46 @@ export class Gateway extends Connector {
81
103
  .catch(rethrow) as http.OutgoingMessage
82
104
  }
83
105
 
106
+ private async explain (node: Node, parameters: Parameter[]): Promise<http.OutgoingMessage> {
107
+ const body = await node.explain(parameters)
108
+ const allow = [...Object.keys(node.methods)].join(', ')
109
+ const headers = new Headers({ allow })
110
+
111
+ return { body, headers }
112
+ }
113
+
84
114
  private async discover (): Promise<void> {
85
115
  await this.broadcast.receive<Branch>('expose', this.merge.bind(this))
86
116
  await this.broadcast.transmit<null>('ping', null)
87
117
  }
88
118
 
89
119
  private merge (branch: Branch): void {
120
+ const id = branch.namespace + '.' + branch.component + '@' + branch.version
121
+
122
+ if (this.merged.has(id)) {
123
+ console.debug('Branch already merged, ignoring', {
124
+ namespace: branch.namespace,
125
+ component: branch.component,
126
+ version: branch.version
127
+ })
128
+
129
+ return
130
+ }
131
+
132
+ this.merged.add(id)
133
+
134
+ const attributes = {
135
+ namespace: branch.namespace,
136
+ component: branch.component,
137
+ version: branch.version
138
+ }
139
+
90
140
  try {
91
141
  this.tree.merge(branch.node, branch)
92
142
 
93
- console.info('Resource branch of ' +
94
- `'${branch.namespace}.${branch.component}' has been merged.`)
95
- } catch (exception) {
96
- console.error(exception)
143
+ console.info('Branch merged', attributes)
144
+ } catch (exception: unknown) {
145
+ console.error('Branch merge exception', { exception, ...attributes })
97
146
  }
98
147
  }
99
148
  }
@@ -1,4 +1,5 @@
1
1
  import Negotiator from 'negotiator'
2
+ import { console } from 'openspan'
2
3
  import { Timing } from './Timing'
3
4
  import { type Format, formats, types } from './formats'
4
5
  import { read } from './messages'
@@ -6,22 +7,29 @@ import type { OutgoingMessage } from './messages'
6
7
  import type * as http from 'node:http'
7
8
 
8
9
  export class Context {
10
+ public readonly authority: string
9
11
  public readonly request: IncomingMessage
10
12
  public readonly url: URL
11
13
  public readonly subtype: string | null = null
12
14
  public readonly encoder: Format | null = null
13
15
  public readonly timing: Timing
16
+ public readonly debug: boolean
14
17
 
15
18
  public readonly pipelines: Pipelines = {
16
19
  body: [],
17
20
  response: []
18
21
  }
19
22
 
20
- public constructor (request: IncomingMessage, trace = false) {
23
+ public constructor (authority: string, request: IncomingMessage, properties: Properties) {
24
+ this.authority = authority
21
25
  this.request = request
22
26
 
23
27
  this.url = new URL(request.url, `https://${request.headers.host}`)
24
- this.timing = new Timing(trace)
28
+ this.timing = new Timing(properties.trace)
29
+ this.debug = properties.debug
30
+
31
+ if (this.debug)
32
+ this.log(request)
25
33
 
26
34
  if (this.request.headers.accept !== undefined) {
27
35
  const match = SUBTYPE.exec(this.request.headers.accept)
@@ -52,6 +60,16 @@ export class Context {
52
60
  ? value
53
61
  : this.pipelines.body.reduce((value, transform) => transform(value), value)
54
62
  }
63
+
64
+ private log (request: IncomingMessage): void {
65
+ const headers = { ...request.headers }
66
+
67
+ if (headers.authorization !== undefined)
68
+ // only scheme
69
+ headers.authorization = headers.authorization.slice(0, headers.authorization.indexOf(' '))
70
+
71
+ console.debug('Received request', { method: request.method, url: request.url, headers })
72
+ }
55
73
  }
56
74
 
57
75
  export interface IncomingMessage extends http.IncomingMessage {
@@ -61,7 +79,12 @@ export interface IncomingMessage extends http.IncomingMessage {
61
79
 
62
80
  interface Pipelines {
63
81
  body: Array<(input: unknown) => unknown>
64
- response: Array<(output: OutgoingMessage) => void>
82
+ response: Array<(output: OutgoingMessage) => void | Promise<void>>
83
+ }
84
+
85
+ interface Properties {
86
+ debug: boolean
87
+ trace: boolean
65
88
  }
66
89
 
67
90
  const SUBTYPE = /^(?<type>\w{1,32})\/(vnd\.toa\.(?<subtype>\S{1,32})\+)(?<suffix>\S{1,32})$/
@@ -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,26 @@ 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
- }
25
-
26
- public get port (): number {
27
- if (this.properties.port !== 0)
28
- return this.properties.port
29
-
30
- const address = this.server.address()
31
28
 
32
- if (address === null || typeof address === 'string')
33
- throw new Error('Server is not listening on a port.')
34
-
35
- return address.port
29
+ if (this.properties.debug)
30
+ this.server.on('connection', (socket) =>
31
+ console.debug('Connected', { address: socket.remoteAddress }))
36
32
  }
37
33
 
38
- public static create (options?: Partial<Properties>): Server {
39
- const properties = options === undefined
40
- ? DEFAULTS
41
- : { ...DEFAULTS, ...options }
34
+ public static create (options: Options): Server {
35
+ const properties: Properties = Object.assign({}, DEFAULTS, options)
42
36
 
43
37
  return new Server(properties)
44
38
  }
@@ -48,21 +42,29 @@ export class Server extends Connector {
48
42
  }
49
43
 
50
44
  protected override async open (): Promise<void> {
45
+ this.startedAt = Date.now()
51
46
  this.server.listen(this.properties.port)
52
47
 
53
48
  await once(this.server, 'listening')
54
49
 
55
- console.info('HTTP Server is listening.')
50
+ console.info('HTTP Server is listening')
51
+
52
+ await setTimeout(this.properties.delay)
53
+
54
+ this.ready = true
55
+
56
+ console.info('Ready')
56
57
  }
57
58
 
58
59
  protected override async close (): Promise<void> {
59
60
  this.server.close()
61
+ this.ready = false
60
62
 
61
- console.info('HTTP Server stopped accepting new connections.')
63
+ console.info('Stopped accepting new connections')
62
64
 
63
65
  await once(this.server, 'close')
64
66
 
65
- console.info('HTTP Server has been stopped.')
67
+ console.info('Stopped')
66
68
  }
67
69
 
68
70
  private listener (request: http.IncomingMessage, response: http.ServerResponse): void {
@@ -72,24 +74,29 @@ export class Server extends Connector {
72
74
  return
73
75
  }
74
76
 
75
- if (request.url === undefined) {
76
- response.writeHead(400).end()
77
+ if (request.url === '/.ready') {
78
+ if (this.ready)
79
+ response.writeHead(200, { 'cache-control': 'no-store' }).end()
80
+ else {
81
+ const remaining = (Math.ceil((Date.now() - this.startedAt) / 1000)).toString()
82
+
83
+ response.writeHead(503, { 'retry-after': remaining }).end()
84
+ }
77
85
 
78
86
  return
79
87
  }
80
88
 
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)
89
+ const host = request.headers.host!
90
+ const authority = this.authorities[host] ?? host
91
+ const context = new Context(authority, request as IncomingMessage, this.properties)
85
92
 
86
- this.process(context)
93
+ this.process!(context)
87
94
  .then(this.success(context, response))
88
95
  .catch(this.fail(context, response))
89
96
  }
90
97
 
91
98
  private success (context: Context, response: http.ServerResponse) {
92
- return (message: OutgoingMessage) => {
99
+ return async (message: OutgoingMessage) => {
93
100
  let status = message.status
94
101
 
95
102
  if (status === undefined)
@@ -97,13 +104,13 @@ export class Server extends Connector {
97
104
  status = 404
98
105
  else if (context.request.method === 'POST')
99
106
  status = 201
100
- else if (message.body === undefined)
107
+ else if (message.body === undefined && context.request.method !== 'HEAD')
101
108
  status = 204
102
109
  else
103
110
  status = 200
104
111
 
105
112
  response.statusCode = message.status = status
106
- write(context, response, message)
113
+ await write(context, response, message)
107
114
  }
108
115
  }
109
116
 
@@ -112,47 +119,54 @@ export class Server extends Connector {
112
119
  if (!context.request.complete)
113
120
  await adam(context.request)
114
121
 
115
- response.statusCode = exception instanceof Exception
116
- ? exception.status
117
- : 500
122
+ response.statusCode = exception instanceof Exception ? exception.status : 500
118
123
 
119
124
  const message: OutgoingMessage = { status: response.statusCode }
120
- const verbose = exception instanceof ClientError || this.properties.debug
121
125
 
122
- if (verbose)
123
- message.body = exception instanceof Exception
124
- ? exception.body
125
- : (exception.stack ?? exception.message)
126
+ if (context.encoder === null)
127
+ message.body = undefined
128
+ else if (exception instanceof ClientError || this.properties.debug)
129
+ message.body =
130
+ exception instanceof Exception
131
+ ? exception.body
132
+ : exception.stack ?? exception.message
126
133
 
127
- write(context, response, message)
134
+ await write(context, response, message)
128
135
  }
129
136
  }
130
137
  }
131
138
 
132
139
  // https://github.com/whatwg/fetch/issues/1254
133
140
  async function adam (request: http.IncomingMessage): Promise<void> {
134
- const completed = promex()
135
141
  const devnull = fs.createWriteStream(os.devNull)
136
142
 
137
- request
138
- .on('end', completed.callback)
139
- .pipe(devnull)
143
+ request.pipe(devnull)
140
144
 
141
- return completed
145
+ await once(request, 'end')
142
146
  }
143
147
 
144
- const DEFAULTS: Properties = {
145
- methods: new Set<string>(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),
148
+ export const PORT = 8000
149
+ export const DELAY = 3 // seconds
150
+
151
+ const DEFAULTS: Omit<Properties, 'authorities'> = {
152
+ methods: new Set<string>(['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'LOCK', 'UNLOCK']),
146
153
  debug: false,
147
154
  trace: false,
148
- port: 8000
155
+ port: PORT,
156
+ delay: DELAY * 1000
149
157
  }
150
158
 
151
159
  interface Properties {
160
+ authorities: Record<string, string>
152
161
  methods: Set<string>
153
162
  debug: boolean
154
163
  trace: boolean
155
164
  port: number
165
+ delay: number
166
+ }
167
+
168
+ export type Options = { authorities: Properties['authorities'] } & {
169
+ [K in Exclude<keyof Properties, 'authorities'>]?: Properties[K]
156
170
  }
157
171
 
158
172
  export type Processing = (input: Context) => Promise<OutgoingMessage>