@decohere/http 0.0.1-dev.126 → 0.0.1-dev.5

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 (293) hide show
  1. package/README.md +2 -2
  2. package/package.json +4 -13
  3. package/src/app/app.ts +147 -0
  4. package/src/app/module.ts +19 -0
  5. package/src/auth/ability.ts +56 -0
  6. package/src/auth/auth.config.ts +34 -0
  7. package/src/auth/auth.extensions.ts +115 -0
  8. package/src/auth/auth.types.ts +124 -0
  9. package/src/auth/casl-authorization.service.ts +62 -0
  10. package/{types/src/auth/principal-provider.d.ts → src/auth/principal-provider.ts} +13 -5
  11. package/src/auth/safe-outbound-url.ts +117 -0
  12. package/src/auth/token-service.ts +192 -0
  13. package/src/builder/builder.ts +118 -0
  14. package/{es6/src/const.js → src/const.ts} +25 -17
  15. package/src/health/health.controller.ts +34 -0
  16. package/src/health/health.extensions.ts +53 -0
  17. package/src/health/readiness.service.ts +33 -0
  18. package/{types/src/health/readiness.types.d.ts → src/health/readiness.types.ts} +4 -8
  19. package/src/hosting/hosted-service-host.ts +102 -0
  20. package/src/hosting/hosted-service.ts +31 -0
  21. package/src/http/http.compression.ts +38 -0
  22. package/src/http/http.extensions.ts +244 -0
  23. package/{types/src/http/http.options.store.d.ts → src/http/http.options.store.ts} +11 -1
  24. package/src/http/http.options.ts +41 -0
  25. package/{types/src/http/http.security.d.ts → src/http/http.security.ts} +16 -10
  26. package/src/http/http.static.ts +359 -0
  27. package/{es6/src/index.js → src/index.ts} +1 -0
  28. package/src/openapi/index.ts +22 -0
  29. package/src/openapi/openapi.generator.ts +78 -0
  30. package/src/openapi/openapi.types.ts +60 -0
  31. package/src/openapi/request-schema.ts +155 -0
  32. package/src/openapi/request-validator.ts +95 -0
  33. package/src/providers/fastify.provider.ts +454 -0
  34. package/src/routing/anvil.types.ts +150 -0
  35. package/src/routing/decorators/argument.decorator.ts +33 -0
  36. package/src/routing/decorators/auth.decorator.ts +79 -0
  37. package/src/routing/decorators/controller.decorator.ts +9 -0
  38. package/src/routing/decorators/field.decorator.ts +15 -0
  39. package/src/routing/decorators/request.decorator.ts +34 -0
  40. package/src/routing/decorators/response.decorator.ts +18 -0
  41. package/src/routing/decorators/route.decorator.ts +52 -0
  42. package/src/routing/filters/exception-filter-host.ts +90 -0
  43. package/src/routing/filters/exception-filter.ts +29 -0
  44. package/src/routing/middleware/http-access-log.middleware.ts +36 -0
  45. package/src/routing/middleware/middleware.ts +26 -0
  46. package/src/routing/middleware/request-id.ts +18 -0
  47. package/src/routing/path.util.ts +38 -0
  48. package/src/routing/pipes/pipes.ts +132 -0
  49. package/src/routing/services/route-argument-resolver.ts +92 -0
  50. package/src/routing/services/route-registry.ts +229 -0
  51. package/src/routing/services/router.ts +166 -0
  52. package/src/sse/sse.decorator.ts +41 -0
  53. package/src/sse/sse.encoder.ts +86 -0
  54. package/src/sse/sse.types.ts +47 -0
  55. package/src/sse/sse.wire.ts +34 -0
  56. package/src/testing/boot-module.ts +63 -0
  57. package/src/testing/sse-reader.ts +120 -0
  58. package/tests/app.hosted-services.spec.ts +292 -0
  59. package/tests/app.shutdown.integration.spec.ts +160 -0
  60. package/tests/app.spec.ts +132 -0
  61. package/tests/auth.ability.spec.ts +48 -0
  62. package/tests/auth.decorators.spec.ts +20 -0
  63. package/tests/auth.fail-closed.pentest.spec.ts +77 -0
  64. package/tests/auth.integration.spec.ts +234 -0
  65. package/tests/auth.jwks-cache.spec.ts +52 -0
  66. package/tests/auth.missing-auth.pentest.spec.ts +56 -0
  67. package/tests/auth.oidc-ssrf.pentest.spec.ts +72 -0
  68. package/tests/auth.oidc.integration.spec.ts +161 -0
  69. package/tests/auth.token-service.spec.ts +251 -0
  70. package/tests/builder.spec.ts +12 -0
  71. package/tests/health.integration.spec.ts +111 -0
  72. package/tests/helpers/listen-ephemeral.ts +13 -0
  73. package/tests/helpers/local-oidc-server.ts +100 -0
  74. package/tests/http.access-log.integration.spec.ts +111 -0
  75. package/tests/http.boolean-query.integration.spec.ts +59 -0
  76. package/tests/http.compression.integration.spec.ts +604 -0
  77. package/tests/http.date-query.integration.spec.ts +71 -0
  78. package/tests/http.global-prefix.integration.spec.ts +284 -0
  79. package/tests/http.number-query.integration.spec.ts +65 -0
  80. package/tests/http.pino-roll-hmr.integration.spec.ts +79 -0
  81. package/tests/http.pipeline-order.integration.spec.ts +95 -0
  82. package/tests/http.request-cleanup.integration.spec.ts +57 -0
  83. package/tests/http.request-id-scope.pentest.spec.ts +50 -0
  84. package/tests/http.security.integration.spec.ts +106 -0
  85. package/tests/http.static.integration.spec.ts +847 -0
  86. package/tests/http.static.spec.ts +111 -0
  87. package/tests/http.surface.integration.spec.ts +167 -0
  88. package/tests/openapi.integration.spec.ts +193 -0
  89. package/tests/openapi.validator-cache.integration.spec.ts +55 -0
  90. package/tests/routing.decorators.spec.ts +15 -0
  91. package/tests/routing.registry.spec.ts +44 -0
  92. package/tests/routing.resolver.spec.ts +92 -0
  93. package/tests/sse.integration.spec.ts +421 -0
  94. package/tests/sse.wire.spec.ts +33 -0
  95. package/LICENSE +0 -15
  96. package/commonjs/src/app/app.js +0 -166
  97. package/commonjs/src/app/index.js +0 -19
  98. package/commonjs/src/app/module.js +0 -17
  99. package/commonjs/src/auth/ability.js +0 -54
  100. package/commonjs/src/auth/auth.config.js +0 -23
  101. package/commonjs/src/auth/auth.extensions.js +0 -106
  102. package/commonjs/src/auth/auth.types.js +0 -65
  103. package/commonjs/src/auth/casl-authorization.service.js +0 -36
  104. package/commonjs/src/auth/index.js +0 -23
  105. package/commonjs/src/auth/principal-provider.js +0 -19
  106. package/commonjs/src/auth/safe-outbound-url.js +0 -102
  107. package/commonjs/src/auth/token-service.js +0 -151
  108. package/commonjs/src/builder/builder.js +0 -95
  109. package/commonjs/src/builder/index.js +0 -18
  110. package/commonjs/src/const.js +0 -87
  111. package/commonjs/src/health/health.controller.js +0 -75
  112. package/commonjs/src/health/health.extensions.js +0 -50
  113. package/commonjs/src/health/index.js +0 -21
  114. package/commonjs/src/health/readiness.service.js +0 -67
  115. package/commonjs/src/health/readiness.types.js +0 -7
  116. package/commonjs/src/hosting/hosted-service-host.js +0 -88
  117. package/commonjs/src/hosting/hosted-service.js +0 -11
  118. package/commonjs/src/hosting/index.js +0 -19
  119. package/commonjs/src/http/http.compression.js +0 -27
  120. package/commonjs/src/http/http.extensions.js +0 -269
  121. package/commonjs/src/http/http.options.js +0 -26
  122. package/commonjs/src/http/http.options.store.js +0 -20
  123. package/commonjs/src/http/http.security.js +0 -27
  124. package/commonjs/src/http/http.static.js +0 -248
  125. package/commonjs/src/http/index.js +0 -22
  126. package/commonjs/src/index.js +0 -27
  127. package/commonjs/src/openapi/index.js +0 -45
  128. package/commonjs/src/openapi/openapi.generator.js +0 -103
  129. package/commonjs/src/openapi/openapi.types.js +0 -4
  130. package/commonjs/src/openapi/request-schema.js +0 -187
  131. package/commonjs/src/openapi/request-validator.js +0 -85
  132. package/commonjs/src/providers/fastify.provider.js +0 -391
  133. package/commonjs/src/providers/index.js +0 -18
  134. package/commonjs/src/routing/anvil.types.js +0 -99
  135. package/commonjs/src/routing/decorators/argument.decorator.js +0 -49
  136. package/commonjs/src/routing/decorators/auth.decorator.js +0 -70
  137. package/commonjs/src/routing/decorators/controller.decorator.js +0 -16
  138. package/commonjs/src/routing/decorators/field.decorator.js +0 -25
  139. package/commonjs/src/routing/decorators/index.js +0 -24
  140. package/commonjs/src/routing/decorators/request.decorator.js +0 -30
  141. package/commonjs/src/routing/decorators/response.decorator.js +0 -34
  142. package/commonjs/src/routing/decorators/route.decorator.js +0 -67
  143. package/commonjs/src/routing/filters/exception-filter-host.js +0 -145
  144. package/commonjs/src/routing/filters/exception-filter.js +0 -28
  145. package/commonjs/src/routing/index.js +0 -25
  146. package/commonjs/src/routing/middleware/http-access-log.middleware.js +0 -47
  147. package/commonjs/src/routing/middleware/middleware.js +0 -20
  148. package/commonjs/src/routing/middleware/request-id.js +0 -30
  149. package/commonjs/src/routing/path.util.js +0 -51
  150. package/commonjs/src/routing/pipes/index.js +0 -18
  151. package/commonjs/src/routing/pipes/pipes.js +0 -145
  152. package/commonjs/src/routing/services/index.js +0 -18
  153. package/commonjs/src/routing/services/route-argument-resolver.js +0 -77
  154. package/commonjs/src/routing/services/route-registry.js +0 -194
  155. package/commonjs/src/routing/services/router.js +0 -158
  156. package/commonjs/src/sse/index.js +0 -26
  157. package/commonjs/src/sse/sse.decorator.js +0 -42
  158. package/commonjs/src/sse/sse.encoder.js +0 -73
  159. package/commonjs/src/sse/sse.types.js +0 -36
  160. package/commonjs/src/sse/sse.wire.js +0 -40
  161. package/commonjs/src/testing/boot-module.js +0 -38
  162. package/commonjs/src/testing/index.js +0 -20
  163. package/commonjs/src/testing/sse-reader.js +0 -98
  164. package/es6/src/app/app.js +0 -148
  165. package/es6/src/app/index.js +0 -2
  166. package/es6/src/app/module.js +0 -7
  167. package/es6/src/auth/ability.js +0 -45
  168. package/es6/src/auth/auth.config.js +0 -19
  169. package/es6/src/auth/auth.extensions.js +0 -83
  170. package/es6/src/auth/auth.types.js +0 -35
  171. package/es6/src/auth/casl-authorization.service.js +0 -40
  172. package/es6/src/auth/index.js +0 -6
  173. package/es6/src/auth/principal-provider.js +0 -14
  174. package/es6/src/auth/safe-outbound-url.js +0 -99
  175. package/es6/src/auth/token-service.js +0 -141
  176. package/es6/src/builder/builder.js +0 -85
  177. package/es6/src/builder/index.js +0 -1
  178. package/es6/src/health/health.controller.js +0 -65
  179. package/es6/src/health/health.extensions.js +0 -40
  180. package/es6/src/health/index.js +0 -4
  181. package/es6/src/health/readiness.service.js +0 -57
  182. package/es6/src/health/readiness.types.js +0 -4
  183. package/es6/src/hosting/hosted-service-host.js +0 -81
  184. package/es6/src/hosting/hosted-service.js +0 -8
  185. package/es6/src/hosting/index.js +0 -2
  186. package/es6/src/http/http.compression.js +0 -9
  187. package/es6/src/http/http.extensions.js +0 -259
  188. package/es6/src/http/http.options.js +0 -16
  189. package/es6/src/http/http.options.store.js +0 -13
  190. package/es6/src/http/http.security.js +0 -9
  191. package/es6/src/http/http.static.js +0 -224
  192. package/es6/src/http/index.js +0 -5
  193. package/es6/src/openapi/index.js +0 -3
  194. package/es6/src/openapi/openapi.generator.js +0 -82
  195. package/es6/src/openapi/openapi.types.js +0 -1
  196. package/es6/src/openapi/request-schema.js +0 -160
  197. package/es6/src/openapi/request-validator.js +0 -71
  198. package/es6/src/providers/fastify.provider.js +0 -376
  199. package/es6/src/providers/index.js +0 -1
  200. package/es6/src/routing/anvil.types.js +0 -57
  201. package/es6/src/routing/decorators/argument.decorator.js +0 -28
  202. package/es6/src/routing/decorators/auth.decorator.js +0 -58
  203. package/es6/src/routing/decorators/controller.decorator.js +0 -6
  204. package/es6/src/routing/decorators/field.decorator.js +0 -15
  205. package/es6/src/routing/decorators/index.js +0 -7
  206. package/es6/src/routing/decorators/request.decorator.js +0 -24
  207. package/es6/src/routing/decorators/response.decorator.js +0 -16
  208. package/es6/src/routing/decorators/route.decorator.js +0 -37
  209. package/es6/src/routing/filters/exception-filter-host.js +0 -127
  210. package/es6/src/routing/filters/exception-filter.js +0 -10
  211. package/es6/src/routing/index.js +0 -8
  212. package/es6/src/routing/middleware/http-access-log.middleware.js +0 -37
  213. package/es6/src/routing/middleware/middleware.js +0 -10
  214. package/es6/src/routing/middleware/request-id.js +0 -14
  215. package/es6/src/routing/path.util.js +0 -33
  216. package/es6/src/routing/pipes/index.js +0 -1
  217. package/es6/src/routing/pipes/pipes.js +0 -118
  218. package/es6/src/routing/services/index.js +0 -1
  219. package/es6/src/routing/services/route-argument-resolver.js +0 -67
  220. package/es6/src/routing/services/route-registry.js +0 -184
  221. package/es6/src/routing/services/router.js +0 -148
  222. package/es6/src/sse/index.js +0 -2
  223. package/es6/src/sse/sse.decorator.js +0 -31
  224. package/es6/src/sse/sse.encoder.js +0 -67
  225. package/es6/src/sse/sse.types.js +0 -22
  226. package/es6/src/sse/sse.wire.js +0 -30
  227. package/es6/src/testing/boot-module.js +0 -35
  228. package/es6/src/testing/index.js +0 -2
  229. package/es6/src/testing/sse-reader.js +0 -91
  230. package/types/src/app/app.d.ts +0 -41
  231. package/types/src/app/module.d.ts +0 -15
  232. package/types/src/auth/ability.d.ts +0 -19
  233. package/types/src/auth/auth.config.d.ts +0 -28
  234. package/types/src/auth/auth.extensions.d.ts +0 -53
  235. package/types/src/auth/auth.types.d.ts +0 -73
  236. package/types/src/auth/casl-authorization.service.d.ts +0 -28
  237. package/types/src/auth/safe-outbound-url.d.ts +0 -9
  238. package/types/src/auth/token-service.d.ts +0 -31
  239. package/types/src/builder/builder.d.ts +0 -36
  240. package/types/src/const.d.ts +0 -32
  241. package/types/src/health/health.controller.d.ts +0 -16
  242. package/types/src/health/health.extensions.d.ts +0 -31
  243. package/types/src/health/readiness.service.d.ts +0 -9
  244. package/types/src/hosting/hosted-service-host.d.ts +0 -37
  245. package/types/src/hosting/hosted-service.d.ts +0 -31
  246. package/types/src/http/http.compression.d.ts +0 -32
  247. package/types/src/http/http.extensions.d.ts +0 -79
  248. package/types/src/http/http.options.d.ts +0 -39
  249. package/types/src/http/http.static.d.ts +0 -160
  250. package/types/src/index.d.ts +0 -10
  251. package/types/src/openapi/index.d.ts +0 -6
  252. package/types/src/openapi/openapi.generator.d.ts +0 -6
  253. package/types/src/openapi/openapi.types.d.ts +0 -58
  254. package/types/src/openapi/request-schema.d.ts +0 -21
  255. package/types/src/openapi/request-validator.d.ts +0 -9
  256. package/types/src/providers/fastify.provider.d.ts +0 -56
  257. package/types/src/routing/anvil.types.d.ts +0 -119
  258. package/types/src/routing/decorators/argument.decorator.d.ts +0 -11
  259. package/types/src/routing/decorators/auth.decorator.d.ts +0 -30
  260. package/types/src/routing/decorators/controller.decorator.d.ts +0 -3
  261. package/types/src/routing/decorators/field.decorator.d.ts +0 -2
  262. package/types/src/routing/decorators/request.decorator.d.ts +0 -8
  263. package/types/src/routing/decorators/response.decorator.d.ts +0 -4
  264. package/types/src/routing/decorators/route.decorator.d.ts +0 -7
  265. package/types/src/routing/filters/exception-filter-host.d.ts +0 -19
  266. package/types/src/routing/filters/exception-filter.d.ts +0 -16
  267. package/types/src/routing/middleware/http-access-log.middleware.d.ts +0 -8
  268. package/types/src/routing/middleware/middleware.d.ts +0 -10
  269. package/types/src/routing/middleware/request-id.d.ts +0 -6
  270. package/types/src/routing/path.util.d.ts +0 -9
  271. package/types/src/routing/pipes/pipes.d.ts +0 -21
  272. package/types/src/routing/services/route-argument-resolver.d.ts +0 -10
  273. package/types/src/routing/services/route-registry.d.ts +0 -20
  274. package/types/src/routing/services/router.d.ts +0 -22
  275. package/types/src/sse/sse.decorator.d.ts +0 -17
  276. package/types/src/sse/sse.encoder.d.ts +0 -16
  277. package/types/src/sse/sse.types.d.ts +0 -37
  278. package/types/src/sse/sse.wire.d.ts +0 -9
  279. package/types/src/testing/boot-module.d.ts +0 -34
  280. package/types/src/testing/sse-reader.d.ts +0 -29
  281. /package/{types/src/app/index.d.ts → src/app/index.ts} +0 -0
  282. /package/{types/src/auth/index.d.ts → src/auth/index.ts} +0 -0
  283. /package/{types/src/builder/index.d.ts → src/builder/index.ts} +0 -0
  284. /package/{types/src/health/index.d.ts → src/health/index.ts} +0 -0
  285. /package/{types/src/hosting/index.d.ts → src/hosting/index.ts} +0 -0
  286. /package/{types/src/http/index.d.ts → src/http/index.ts} +0 -0
  287. /package/{types/src/providers/index.d.ts → src/providers/index.ts} +0 -0
  288. /package/{types/src/routing/decorators/index.d.ts → src/routing/decorators/index.ts} +0 -0
  289. /package/{types/src/routing/index.d.ts → src/routing/index.ts} +0 -0
  290. /package/{types/src/routing/pipes/index.d.ts → src/routing/pipes/index.ts} +0 -0
  291. /package/{types/src/routing/services/index.d.ts → src/routing/services/index.ts} +0 -0
  292. /package/{types/src/sse/index.d.ts → src/sse/index.ts} +0 -0
  293. /package/{types/src/testing/index.d.ts → src/testing/index.ts} +0 -0
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- _export_star(require("./router.js"), exports);
6
- function _export_star(from, to) {
7
- Object.keys(from).forEach(function(k) {
8
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
9
- Object.defineProperty(to, k, {
10
- enumerable: true,
11
- get: function() {
12
- return from[k];
13
- }
14
- });
15
- }
16
- });
17
- return from;
18
- }
@@ -1,77 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "RouteArgumentResolve", {
6
- enumerable: true,
7
- get: function() {
8
- return RouteArgumentResolve;
9
- }
10
- });
11
- const _reflection = require("@decohere/core/reflection");
12
- class RouteArgumentResolve {
13
- resolveArguments(httpRequest, routeArgs, principalProvider) {
14
- const argsValues = [];
15
- for (const [argIdx, routeArg] of routeArgs.entries()){
16
- const val = this.getValue(httpRequest, routeArg, principalProvider);
17
- argsValues[argIdx] = val;
18
- }
19
- return argsValues;
20
- }
21
- getValue(httpRequest, routeArg, principalProvider) {
22
- switch(routeArg.argumentLocation){
23
- case "principal":
24
- return principalProvider?.currentPrincipal;
25
- case "signal":
26
- return httpRequest.signal;
27
- case "lastEventId":
28
- return httpRequest.headers["last-event-id"];
29
- }
30
- const value = (0, _reflection.isPrimitiveOrDateType)(routeArg.argumentType) ? this.mapPrimitive(httpRequest, routeArg) : this.mapObject(httpRequest, routeArg);
31
- return value;
32
- }
33
- mapPrimitive(httpRequest, routeArg) {
34
- const { argumentLocation, mappingKey, pipes } = routeArg;
35
- const value = httpRequest[argumentLocation][mappingKey];
36
- const tranformedValue = this.transform(value, pipes, routeArg.fieldMap);
37
- return tranformedValue;
38
- }
39
- mapObject(httpRequest, routeArg) {
40
- const { argumentType } = routeArg;
41
- const inst = new argumentType();
42
- const { fieldMap } = routeArg;
43
- for (const [fieldKey, meta] of fieldMap.entries()){
44
- const { fieldLocation, mappingKey, pipes } = meta;
45
- const value = httpRequest[fieldLocation][mappingKey];
46
- const transformedValue = this.transform(value, pipes, fieldMap);
47
- inst[fieldKey] = transformedValue;
48
- }
49
- return inst;
50
- }
51
- transform(value, pipes, fieldMap) {
52
- let transformed = value;
53
- if (value == null) {
54
- return value;
55
- }
56
- const context = this.pipeContext(fieldMap);
57
- for (const pipeConstructor of pipes ?? []){
58
- const pipe = new pipeConstructor();
59
- transformed = pipe.transform(transformed, context);
60
- }
61
- return transformed;
62
- }
63
- pipeContext(fieldMap) {
64
- if (fieldMap == null || fieldMap.size === 0) {
65
- return undefined;
66
- }
67
- const fieldTypes = {};
68
- for (const [key, meta] of fieldMap.entries()){
69
- if (meta.fieldType != null) {
70
- fieldTypes[key] = meta.fieldType;
71
- }
72
- }
73
- return Object.keys(fieldTypes).length > 0 ? {
74
- fieldTypes
75
- } : undefined;
76
- }
77
- }
@@ -1,194 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "RouteRegistry", {
6
- enumerable: true,
7
- get: function() {
8
- return RouteRegistry;
9
- }
10
- });
11
- const _decorators = require("@decohere/crucible/decorators");
12
- const _reflection = require("@decohere/core/reflection");
13
- const _const = require("../../const.js");
14
- const _anviltypes = require("../anvil.types.js");
15
- const _pathutil = require("../path.util.js");
16
- const _pipes = require("../pipes/pipes.js");
17
- function _ts_decorate(decorators, target, key, desc) {
18
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
- return c > 3 && r && Object.defineProperty(target, key, r), r;
22
- }
23
- function _ts_metadata(k, v) {
24
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
- }
26
- function _ts_param(paramIndex, decorator) {
27
- return function(target, key) {
28
- decorator(target, key, paramIndex);
29
- };
30
- }
31
- class RouteRegistry {
32
- routeMap = new Map();
33
- httpOptions;
34
- constructor(httpOptions){
35
- this.httpOptions = httpOptions;
36
- }
37
- addController(controller) {
38
- const funcs = (0, _reflection.getFunctions)(controller);
39
- for (const func of funcs){
40
- this.addControllerRoute(controller, func);
41
- }
42
- }
43
- get routes() {
44
- return this.routeMap.values();
45
- }
46
- getRoute(key) {
47
- return this.routeMap.get(key);
48
- }
49
- addControllerRoute(controller, prop) {
50
- const func = prop.value;
51
- const handler = func.name;
52
- const route = (0, _reflection.getMeta)(_const.MetadataKeys.route, func);
53
- if (route == null) {
54
- return;
55
- }
56
- const globalPrefix = this.takesGlobalPrefix(controller) ? (0, _pathutil.normalizePrefix)(this.httpOptions?.globalPrefix) : "";
57
- const controllerPrefix = this.getControllerPrefix(controller);
58
- const path = (0, _pathutil.applyGlobalPrefix)(globalPrefix, (0, _pathutil.joinRoutePath)(controllerPrefix, route.path));
59
- const { method } = route;
60
- const key = `${method}|${path}`;
61
- const existing = this.routeMap.get(key);
62
- if (existing != null) {
63
- // Last one used to win silently, leaving the other handler unreachable.
64
- throw new _anviltypes.RouteConfigurationError(`Duplicate route ${method.toUpperCase()} ${path}: ${existing.controller.name}.${existing.handler} and ${controller.name}.${handler}`);
65
- }
66
- const routeArgs = this.getRouteArguments(controller, func);
67
- const httpCode = (0, _reflection.getMeta)(_const.MetadataKeys.httpCode, func);
68
- const headers = (0, _reflection.getMeta)(_const.MetadataKeys.headers, func);
69
- const sse = (0, _reflection.getMeta)(_const.MetadataKeys.sse, func);
70
- this.routeMap.set(key, {
71
- key,
72
- controller,
73
- handler,
74
- path,
75
- method,
76
- routeArgs,
77
- httpCode,
78
- headers,
79
- sse
80
- });
81
- }
82
- /** `@Controller({ globalPrefix: false })` opts out, unless the app put it back under. */ takesGlobalPrefix(controller) {
83
- const meta = (0, _reflection.getMeta)(_const.MetadataKeys.controller, controller.prototype);
84
- return meta?.globalPrefix !== false || this.httpOptions?.underGlobalPrefix.has(controller) === true;
85
- }
86
- getControllerPrefix(controller) {
87
- const meta = (0, _reflection.getMeta)(_const.MetadataKeys.controller, controller.prototype);
88
- if (meta?.prefix) {
89
- return (0, _pathutil.normalizePrefix)(meta.prefix);
90
- }
91
- const controllerName = controller.name.toLowerCase().replace("controller", "");
92
- return controllerName !== "" ? `/${controllerName}` : "";
93
- }
94
- getRouteArguments(controller, handler) {
95
- const types = (0, _reflection.getFunctionArgs)(controller.prototype, handler) ?? [];
96
- const args = [];
97
- for (const [argumentIndex, argumentType] of types.entries()){
98
- const argMeta = (0, _reflection.getArgumentMeta)(_const.MetadataKeys.parameter, handler, argumentIndex);
99
- if (argMeta == null && !(0, _reflection.isConstructable)(argumentType)) {
100
- continue;
101
- }
102
- args.push(this.getRouteArgument(argumentType, argumentIndex, handler));
103
- }
104
- return args;
105
- }
106
- getRouteArgument(argumentType, argumentIndex, handler) {
107
- const argMeta = (0, _reflection.getArgumentMeta)(_const.MetadataKeys.parameter, handler, argumentIndex);
108
- // @CurrentUser() / interface params are Object (or other non-DTO types) — no field map.
109
- if (isInjectedPart(argMeta?.argumentLocation) || !(0, _reflection.isConstructable)(argumentType)) {
110
- return {
111
- ...argMeta,
112
- pipes: [],
113
- argumentIndex,
114
- argumentType: (0, _reflection.isConstructable)(argumentType) ? argumentType : Object,
115
- fieldMap: new Map()
116
- };
117
- }
118
- const pipes = argMeta != null ? this.getDefaultPipes(argumentType) : [];
119
- const fieldMap = this.getFields(argumentType, argumentIndex, argMeta);
120
- const routeArg = {
121
- ...argMeta,
122
- pipes,
123
- argumentIndex,
124
- argumentType,
125
- fieldMap
126
- };
127
- return routeArg;
128
- }
129
- getFields(argumentType, argumentIndex, argMeta) {
130
- const inst = new argumentType();
131
- const fields = (0, _reflection.getFields)(inst);
132
- const fieldMap = (0, _reflection.getMeta)(_const.MetadataKeys.fieldMap, argumentType.prototype) ?? new Map();
133
- for (const field of fields){
134
- const fieldKey = field.key;
135
- const fieldMeta = fieldMap.get(field.key);
136
- if (fieldMeta && fieldMeta.fieldLocation == null && argMeta?.argumentLocation == null) {
137
- throw new _anviltypes.RouteConfigurationError(`field ${fieldMeta.fieldKey} must specify a location because location was not specified for the route argument at idx ${argumentIndex}`);
138
- }
139
- const enriched = this.enrichField(field, fieldMeta, argMeta);
140
- fieldMap.set(fieldKey, enriched);
141
- }
142
- return fieldMap;
143
- }
144
- enrichField(field, fieldMeta, argMeta) {
145
- const fieldLocation = fieldMeta?.fieldLocation ?? argMeta.argumentLocation;
146
- const pipes = this.getDefaultPipes(fieldMeta?.fieldType);
147
- return {
148
- fieldKey: field.key,
149
- mappingKey: field.key,
150
- ...fieldMeta,
151
- fieldLocation,
152
- pipes
153
- };
154
- }
155
- getDefaultPipes(argumentType) {
156
- if (argumentType == null) {
157
- return [];
158
- }
159
- let pipe;
160
- if (!(0, _reflection.isPrimitiveOrDateType)(argumentType)) {
161
- pipe = _pipes.JsonPipe;
162
- return [
163
- pipe
164
- ];
165
- }
166
- switch(argumentType.name){
167
- case "Number":
168
- pipe = _pipes.NumberPipe;
169
- break;
170
- case "Boolean":
171
- pipe = _pipes.BooleanPipe;
172
- break;
173
- case "Date":
174
- pipe = _pipes.DatePipe;
175
- break;
176
- default:
177
- return [];
178
- }
179
- return [
180
- pipe
181
- ];
182
- }
183
- }
184
- RouteRegistry = _ts_decorate([
185
- (0, _decorators.injectable)(),
186
- _ts_param(0, (0, _decorators.inject)(_const.HttpOptionsToken)),
187
- _ts_metadata("design:type", Function),
188
- _ts_metadata("design:paramtypes", [
189
- typeof HttpOptions === "undefined" ? Object : HttpOptions
190
- ])
191
- ], RouteRegistry);
192
- function isInjectedPart(location) {
193
- return location != null && _anviltypes.InjectedParts.includes(location);
194
- }
@@ -1,158 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "Router", {
6
- enumerable: true,
7
- get: function() {
8
- return Router;
9
- }
10
- });
11
- const _crucible = require("@decohere/crucible");
12
- const _decorators = require("@decohere/crucible/decorators");
13
- const _scribe = require("@decohere/scribe");
14
- const _const = require("../../const.js");
15
- const _requestvalidator = require("../../openapi/request-validator.js");
16
- const _ssetypes = require("../../sse/sse.types.js");
17
- const _anviltypes = require("../anvil.types.js");
18
- const _authdecorator = require("../decorators/auth.decorator.js");
19
- const _middleware = require("../middleware/middleware.js");
20
- const _routeargumentresolver = require("./route-argument-resolver.js");
21
- const _routeregistry = require("./route-registry.js");
22
- function _ts_decorate(decorators, target, key, desc) {
23
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
24
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
25
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
26
- return c > 3 && r && Object.defineProperty(target, key, r), r;
27
- }
28
- function _ts_metadata(k, v) {
29
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
30
- }
31
- function _ts_param(paramIndex, decorator) {
32
- return function(target, key) {
33
- decorator(target, key, paramIndex);
34
- };
35
- }
36
- class Router {
37
- argResolver = new _routeargumentresolver.RouteArgumentResolve();
38
- lifetimeScope;
39
- routeRegistry;
40
- authService;
41
- httpOptions;
42
- logger = _scribe.scribe.logger(Router.name);
43
- constructor(routeRegistry, lifetimeScope, authService, httpOptions){
44
- this.routeRegistry = routeRegistry;
45
- this.lifetimeScope = lifetimeScope;
46
- this.authService = authService;
47
- this.httpOptions = httpOptions;
48
- this.assertAuthConfiguredForProtectedRoutes();
49
- }
50
- /**
51
- * Without an authorization service nothing checks tokens, so a route marked @Authorize
52
- * would be served to anyone. Refuse to start instead of failing open.
53
- */ assertAuthConfiguredForProtectedRoutes() {
54
- if (this.authService != null) {
55
- return;
56
- }
57
- const protectedRoutes = [
58
- ...this.routeRegistry.routes
59
- ].filter(({ controller, handler })=>(0, _authdecorator.getAuthorizeOptions)(controller.prototype, controller.prototype[handler])).map(({ controller, handler })=>`${controller.name}.${String(handler)}`);
60
- if (protectedRoutes.length > 0) {
61
- throw new _anviltypes.RoutingError(`Routes use @Authorize but auth is not configured, so they would be open to anyone: ${protectedRoutes.join(", ")}. Add .withAuth() to the builder, or remove @Authorize.`);
62
- }
63
- }
64
- async route(routeKey, httpRequest) {
65
- const routeConfig = this.routeRegistry.getRoute(routeKey);
66
- if (!routeConfig) {
67
- throw new _anviltypes.RoutingError(`Route was not configured for key ${routeKey}`);
68
- }
69
- const { controller, handler, routeArgs } = routeConfig;
70
- // Unnamed: the request id comes from the client, so it is not unique.
71
- // Disposed before we respond, so async cleanup (e.g. rolling back a DB transaction)
72
- // finishes first. An SSE route is the exception: its scope lives as long as the stream.
73
- const scope = this.lifetimeScope.beginScope();
74
- let scopeHandedOff = false;
75
- // Runs inside the middleware chain so rejections (401/403/400) reach middleware such as
76
- // the access log. Auth comes first so anonymous callers learn nothing about the body.
77
- const handle = async ()=>{
78
- const principal = await this.authorize(routeConfig, httpRequest);
79
- if (this.httpOptions?.openapi?.validateRequests !== false && this.httpOptions?.openapi) {
80
- (0, _requestvalidator.validateRequest)(routeConfig, httpRequest);
81
- }
82
- const provider = scope.resolve(_const.IPrincipalProviderToken);
83
- provider.setPrincipal(principal);
84
- const controllerInstance = scope.resolve(controller);
85
- const func = controllerInstance[handler];
86
- const argValues = this.argResolver.resolveArguments(httpRequest, routeArgs, provider);
87
- try {
88
- const result = await func.apply(controllerInstance, argValues);
89
- if (routeConfig.sse == null) {
90
- return result;
91
- }
92
- if (typeof result?.[Symbol.asyncIterator] !== "function") {
93
- throw new _anviltypes.RoutingError(`${controller.name}.${String(handler)} is marked @Sse() so it must return an AsyncIterable (an async generator method works)`);
94
- }
95
- scopeHandedOff = true;
96
- return new _ssetypes.SseResponse(result, ()=>scope[Symbol.asyncDispose]());
97
- } catch (error) {
98
- this.logger.error(error.message, error.stack);
99
- throw error;
100
- }
101
- };
102
- try {
103
- const middlewares = this.resolveMiddlewares(scope);
104
- if (middlewares.length === 0) {
105
- return await handle();
106
- }
107
- return await (0, _middleware.composeMiddleware)(middlewares, handle, {
108
- request: httpRequest,
109
- route: routeConfig
110
- });
111
- } catch (error) {
112
- // A middleware failed after the handler returned: nobody will consume the stream.
113
- scopeHandedOff = false;
114
- throw error;
115
- } finally{
116
- if (!scopeHandedOff) {
117
- await scope[Symbol.asyncDispose]();
118
- }
119
- }
120
- }
121
- resolveMiddlewares(scope) {
122
- const types = this.httpOptions?.middlewareTypes ?? [];
123
- return types.map((type)=>scope.resolve(type));
124
- }
125
- async authorize(routeConfig, httpRequest) {
126
- // Optional DI may resolve as null when auth is not registered.
127
- if (this.authService == null) {
128
- return;
129
- }
130
- const { controller, handler } = routeConfig;
131
- const handlerFn = controller.prototype[handler];
132
- if ((0, _authdecorator.isAllowAnonymous)(controller.prototype, handlerFn)) {
133
- return;
134
- }
135
- const authOptions = (0, _authdecorator.getAuthorizeOptions)(controller.prototype, handlerFn);
136
- if (authOptions === undefined) {
137
- // Auth is enabled but the route has no @Authorize — require a valid
138
- // token (fail closed) without checking a specific ability.
139
- return this.authService.authenticateRequest(httpRequest);
140
- }
141
- return this.authService.authorizeRequest(httpRequest, authOptions.action, authOptions.subject);
142
- }
143
- }
144
- Router = _ts_decorate([
145
- (0, _decorators.injectable)(),
146
- _ts_param(0, (0, _decorators.inject)(_const.RouteRegistryToken)),
147
- _ts_param(1, (0, _decorators.inject)(_crucible.LifetimeScopeToken)),
148
- _ts_param(2, (0, _decorators.inject)(_const.AuthorizationServiceToken)),
149
- _ts_param(2, (0, _decorators.optional)()),
150
- _ts_param(3, (0, _decorators.inject)(_const.HttpOptionsToken)),
151
- _ts_metadata("design:type", Function),
152
- _ts_metadata("design:paramtypes", [
153
- typeof _routeregistry.RouteRegistry === "undefined" ? Object : _routeregistry.RouteRegistry,
154
- typeof LifetimeScope === "undefined" ? Object : LifetimeScope,
155
- typeof IAuthorizationService === "undefined" ? Object : IAuthorizationService,
156
- typeof HttpOptions === "undefined" ? Object : HttpOptions
157
- ])
158
- ], Router);
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get LastEventId () {
13
- return _ssedecorator.LastEventId;
14
- },
15
- get Signal () {
16
- return _ssedecorator.Signal;
17
- },
18
- get Sse () {
19
- return _ssedecorator.Sse;
20
- },
21
- get SseResponse () {
22
- return _ssetypes.SseResponse;
23
- }
24
- });
25
- const _ssedecorator = require("./sse.decorator.js");
26
- const _ssetypes = require("./sse.types.js");
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get LastEventId () {
13
- return LastEventId;
14
- },
15
- get Signal () {
16
- return Signal;
17
- },
18
- get Sse () {
19
- return Sse;
20
- }
21
- });
22
- const _reflection = require("@decohere/core/reflection");
23
- const _const = require("../const.js");
24
- function Sse(options = {}) {
25
- return (_target, _methodName, descriptor)=>{
26
- (0, _reflection.defineMeta)(_const.MetadataKeys.sse, options, descriptor.value);
27
- };
28
- }
29
- function injected(location) {
30
- return ()=>(target, propertyKey, parameterIndex)=>{
31
- const fn = target[propertyKey];
32
- const meta = {
33
- argumentIndex: parameterIndex,
34
- argumentLocation: location,
35
- mappingKey: undefined,
36
- pipes: []
37
- };
38
- (0, _reflection.defineArgumentMeta)(_const.MetadataKeys.parameter, meta, fn, parameterIndex);
39
- };
40
- }
41
- const Signal = injected("signal");
42
- const LastEventId = injected("lastEventId");
@@ -1,73 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "encodeSse", {
6
- enumerable: true,
7
- get: function() {
8
- return encodeSse;
9
- }
10
- });
11
- const _scribe = require("@decohere/scribe");
12
- const _ssewire = require("./sse.wire.js");
13
- const logger = _scribe.scribe.logger("SseEncoder");
14
- async function* encodeSse(source, options) {
15
- const { signal, heartbeatMs } = options;
16
- const iterator = source[Symbol.asyncIterator]();
17
- let onAbort;
18
- const abortStep = new Promise((resolve)=>{
19
- onAbort = ()=>resolve({
20
- kind: "abort"
21
- });
22
- if (signal.aborted) onAbort();
23
- else signal.addEventListener("abort", onAbort, {
24
- once: true
25
- });
26
- });
27
- let pending;
28
- try {
29
- yield _ssewire.sseWire.formatComment("open");
30
- while(!signal.aborted){
31
- pending ??= iterator.next().then((result)=>({
32
- kind: "item",
33
- result
34
- }));
35
- let timer;
36
- const steps = [
37
- pending,
38
- abortStep
39
- ];
40
- if (heartbeatMs > 0) {
41
- steps.push(new Promise((resolve)=>{
42
- timer = setTimeout(()=>resolve({
43
- kind: "heartbeat"
44
- }), heartbeatMs);
45
- }));
46
- }
47
- let step;
48
- try {
49
- step = await Promise.race(steps);
50
- } finally{
51
- clearTimeout(timer);
52
- }
53
- if (step.kind === "abort") return;
54
- if (step.kind === "heartbeat") {
55
- yield _ssewire.sseWire.formatComment("heartbeat");
56
- continue;
57
- }
58
- pending = undefined;
59
- if (step.result.done) return;
60
- yield _ssewire.sseWire.formatMessage(step.result.value);
61
- }
62
- } catch (error) {
63
- // Headers are already sent, so the only honest thing left is to log and end the stream.
64
- if (!signal.aborted) logger.error("SSE producer failed", error);
65
- } finally{
66
- if (onAbort) signal.removeEventListener("abort", onAbort);
67
- // If the producer has not answered its last `next()`, `return()` waits behind it. That is
68
- // why handlers must pass the signal to whatever they wait on.
69
- options.onProducerStopped(Promise.resolve().then(()=>iterator.return?.()).then(()=>undefined, (error)=>{
70
- if (!signal.aborted) logger.error("SSE producer failed while stopping", error);
71
- }));
72
- }
73
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * One server-sent event. A bare `string` yielded by a handler is shorthand for `{ data }`.
3
- *
4
- * `data` is written as-is when it is a string and as JSON otherwise.
5
- */ "use strict";
6
- Object.defineProperty(exports, "__esModule", {
7
- value: true
8
- });
9
- function _export(target, all) {
10
- for(var name in all)Object.defineProperty(target, name, {
11
- enumerable: true,
12
- get: Object.getOwnPropertyDescriptor(all, name).get
13
- });
14
- }
15
- _export(exports, {
16
- get DEFAULT_SSE_HEARTBEAT_MS () {
17
- return DEFAULT_SSE_HEARTBEAT_MS;
18
- },
19
- get SseResponse () {
20
- return SseResponse;
21
- }
22
- });
23
- const DEFAULT_SSE_HEARTBEAT_MS = 15_000;
24
- class SseResponse {
25
- events;
26
- onRelease;
27
- released;
28
- constructor(events, onRelease){
29
- this.events = events;
30
- this.onRelease = onRelease;
31
- }
32
- /** Safe to call more than once. */ release() {
33
- this.released ??= this.onRelease();
34
- return this.released;
35
- }
36
- }
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "sseWire", {
6
- enumerable: true,
7
- get: function() {
8
- return sseWire;
9
- }
10
- });
11
- /** Line breaks would end a field early, so a client-controlled `id` could inject extra fields. */ function singleLine(value) {
12
- return value.replace(/[\r\n]+/g, " ");
13
- }
14
- function toMessage(item) {
15
- if (typeof item === "object" && item !== null && "data" in item) {
16
- return item;
17
- }
18
- return {
19
- data: item
20
- };
21
- }
22
- /** Encode one event as the text a browser's `EventSource` parses. */ function formatMessage(item) {
23
- const { data, event, id, retry } = toMessage(item);
24
- let frame = "";
25
- if (id != null) frame += `id: ${singleLine(String(id))}\n`;
26
- if (event != null) frame += `event: ${singleLine(event)}\n`;
27
- if (retry != null && Number.isFinite(retry)) frame += `retry: ${Math.trunc(retry)}\n`;
28
- const text = typeof data === "string" ? data : JSON.stringify(data) ?? "";
29
- for (const line of text.split(/\r\n|\r|\n/)){
30
- frame += `data: ${line}\n`;
31
- }
32
- return `${frame}\n`;
33
- }
34
- /** A comment line: ignored by `EventSource`, but it is traffic on the wire. */ function formatComment(text) {
35
- return `: ${singleLine(text)}\n\n`;
36
- }
37
- const sseWire = {
38
- formatMessage,
39
- formatComment
40
- };