@decohere/http 0.0.1-dev.125 → 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 (292) hide show
  1. package/package.json +4 -13
  2. package/src/app/app.ts +147 -0
  3. package/src/app/module.ts +19 -0
  4. package/src/auth/ability.ts +56 -0
  5. package/src/auth/auth.config.ts +34 -0
  6. package/src/auth/auth.extensions.ts +115 -0
  7. package/src/auth/auth.types.ts +124 -0
  8. package/src/auth/casl-authorization.service.ts +62 -0
  9. package/{types/src/auth/principal-provider.d.ts → src/auth/principal-provider.ts} +13 -5
  10. package/src/auth/safe-outbound-url.ts +117 -0
  11. package/src/auth/token-service.ts +192 -0
  12. package/src/builder/builder.ts +118 -0
  13. package/{es6/src/const.js → src/const.ts} +25 -17
  14. package/src/health/health.controller.ts +34 -0
  15. package/src/health/health.extensions.ts +53 -0
  16. package/src/health/readiness.service.ts +33 -0
  17. package/{types/src/health/readiness.types.d.ts → src/health/readiness.types.ts} +4 -8
  18. package/src/hosting/hosted-service-host.ts +102 -0
  19. package/src/hosting/hosted-service.ts +31 -0
  20. package/src/http/http.compression.ts +38 -0
  21. package/src/http/http.extensions.ts +244 -0
  22. package/{types/src/http/http.options.store.d.ts → src/http/http.options.store.ts} +11 -1
  23. package/src/http/http.options.ts +41 -0
  24. package/{types/src/http/http.security.d.ts → src/http/http.security.ts} +16 -10
  25. package/src/http/http.static.ts +359 -0
  26. package/{es6/src/index.js → src/index.ts} +1 -0
  27. package/src/openapi/index.ts +22 -0
  28. package/src/openapi/openapi.generator.ts +78 -0
  29. package/src/openapi/openapi.types.ts +60 -0
  30. package/src/openapi/request-schema.ts +155 -0
  31. package/src/openapi/request-validator.ts +95 -0
  32. package/src/providers/fastify.provider.ts +454 -0
  33. package/src/routing/anvil.types.ts +150 -0
  34. package/src/routing/decorators/argument.decorator.ts +33 -0
  35. package/src/routing/decorators/auth.decorator.ts +79 -0
  36. package/src/routing/decorators/controller.decorator.ts +9 -0
  37. package/src/routing/decorators/field.decorator.ts +15 -0
  38. package/src/routing/decorators/request.decorator.ts +34 -0
  39. package/src/routing/decorators/response.decorator.ts +18 -0
  40. package/src/routing/decorators/route.decorator.ts +52 -0
  41. package/src/routing/filters/exception-filter-host.ts +90 -0
  42. package/src/routing/filters/exception-filter.ts +29 -0
  43. package/src/routing/middleware/http-access-log.middleware.ts +36 -0
  44. package/src/routing/middleware/middleware.ts +26 -0
  45. package/src/routing/middleware/request-id.ts +18 -0
  46. package/src/routing/path.util.ts +38 -0
  47. package/src/routing/pipes/pipes.ts +132 -0
  48. package/src/routing/services/route-argument-resolver.ts +92 -0
  49. package/src/routing/services/route-registry.ts +229 -0
  50. package/src/routing/services/router.ts +166 -0
  51. package/src/sse/sse.decorator.ts +41 -0
  52. package/src/sse/sse.encoder.ts +86 -0
  53. package/src/sse/sse.types.ts +47 -0
  54. package/src/sse/sse.wire.ts +34 -0
  55. package/src/testing/boot-module.ts +63 -0
  56. package/src/testing/sse-reader.ts +120 -0
  57. package/tests/app.hosted-services.spec.ts +292 -0
  58. package/tests/app.shutdown.integration.spec.ts +160 -0
  59. package/tests/app.spec.ts +132 -0
  60. package/tests/auth.ability.spec.ts +48 -0
  61. package/tests/auth.decorators.spec.ts +20 -0
  62. package/tests/auth.fail-closed.pentest.spec.ts +77 -0
  63. package/tests/auth.integration.spec.ts +234 -0
  64. package/tests/auth.jwks-cache.spec.ts +52 -0
  65. package/tests/auth.missing-auth.pentest.spec.ts +56 -0
  66. package/tests/auth.oidc-ssrf.pentest.spec.ts +72 -0
  67. package/tests/auth.oidc.integration.spec.ts +161 -0
  68. package/tests/auth.token-service.spec.ts +251 -0
  69. package/tests/builder.spec.ts +12 -0
  70. package/tests/health.integration.spec.ts +111 -0
  71. package/tests/helpers/listen-ephemeral.ts +13 -0
  72. package/tests/helpers/local-oidc-server.ts +100 -0
  73. package/tests/http.access-log.integration.spec.ts +111 -0
  74. package/tests/http.boolean-query.integration.spec.ts +59 -0
  75. package/tests/http.compression.integration.spec.ts +604 -0
  76. package/tests/http.date-query.integration.spec.ts +71 -0
  77. package/tests/http.global-prefix.integration.spec.ts +284 -0
  78. package/tests/http.number-query.integration.spec.ts +65 -0
  79. package/tests/http.pino-roll-hmr.integration.spec.ts +79 -0
  80. package/tests/http.pipeline-order.integration.spec.ts +95 -0
  81. package/tests/http.request-cleanup.integration.spec.ts +57 -0
  82. package/tests/http.request-id-scope.pentest.spec.ts +50 -0
  83. package/tests/http.security.integration.spec.ts +106 -0
  84. package/tests/http.static.integration.spec.ts +847 -0
  85. package/tests/http.static.spec.ts +111 -0
  86. package/tests/http.surface.integration.spec.ts +167 -0
  87. package/tests/openapi.integration.spec.ts +193 -0
  88. package/tests/openapi.validator-cache.integration.spec.ts +55 -0
  89. package/tests/routing.decorators.spec.ts +15 -0
  90. package/tests/routing.registry.spec.ts +44 -0
  91. package/tests/routing.resolver.spec.ts +92 -0
  92. package/tests/sse.integration.spec.ts +421 -0
  93. package/tests/sse.wire.spec.ts +33 -0
  94. package/LICENSE +0 -15
  95. package/commonjs/src/app/app.js +0 -166
  96. package/commonjs/src/app/index.js +0 -19
  97. package/commonjs/src/app/module.js +0 -17
  98. package/commonjs/src/auth/ability.js +0 -54
  99. package/commonjs/src/auth/auth.config.js +0 -23
  100. package/commonjs/src/auth/auth.extensions.js +0 -106
  101. package/commonjs/src/auth/auth.types.js +0 -65
  102. package/commonjs/src/auth/casl-authorization.service.js +0 -36
  103. package/commonjs/src/auth/index.js +0 -23
  104. package/commonjs/src/auth/principal-provider.js +0 -19
  105. package/commonjs/src/auth/safe-outbound-url.js +0 -102
  106. package/commonjs/src/auth/token-service.js +0 -151
  107. package/commonjs/src/builder/builder.js +0 -95
  108. package/commonjs/src/builder/index.js +0 -18
  109. package/commonjs/src/const.js +0 -87
  110. package/commonjs/src/health/health.controller.js +0 -75
  111. package/commonjs/src/health/health.extensions.js +0 -50
  112. package/commonjs/src/health/index.js +0 -21
  113. package/commonjs/src/health/readiness.service.js +0 -67
  114. package/commonjs/src/health/readiness.types.js +0 -7
  115. package/commonjs/src/hosting/hosted-service-host.js +0 -88
  116. package/commonjs/src/hosting/hosted-service.js +0 -11
  117. package/commonjs/src/hosting/index.js +0 -19
  118. package/commonjs/src/http/http.compression.js +0 -27
  119. package/commonjs/src/http/http.extensions.js +0 -269
  120. package/commonjs/src/http/http.options.js +0 -26
  121. package/commonjs/src/http/http.options.store.js +0 -20
  122. package/commonjs/src/http/http.security.js +0 -27
  123. package/commonjs/src/http/http.static.js +0 -248
  124. package/commonjs/src/http/index.js +0 -22
  125. package/commonjs/src/index.js +0 -27
  126. package/commonjs/src/openapi/index.js +0 -45
  127. package/commonjs/src/openapi/openapi.generator.js +0 -103
  128. package/commonjs/src/openapi/openapi.types.js +0 -4
  129. package/commonjs/src/openapi/request-schema.js +0 -187
  130. package/commonjs/src/openapi/request-validator.js +0 -85
  131. package/commonjs/src/providers/fastify.provider.js +0 -391
  132. package/commonjs/src/providers/index.js +0 -18
  133. package/commonjs/src/routing/anvil.types.js +0 -99
  134. package/commonjs/src/routing/decorators/argument.decorator.js +0 -49
  135. package/commonjs/src/routing/decorators/auth.decorator.js +0 -70
  136. package/commonjs/src/routing/decorators/controller.decorator.js +0 -16
  137. package/commonjs/src/routing/decorators/field.decorator.js +0 -25
  138. package/commonjs/src/routing/decorators/index.js +0 -24
  139. package/commonjs/src/routing/decorators/request.decorator.js +0 -30
  140. package/commonjs/src/routing/decorators/response.decorator.js +0 -34
  141. package/commonjs/src/routing/decorators/route.decorator.js +0 -67
  142. package/commonjs/src/routing/filters/exception-filter-host.js +0 -145
  143. package/commonjs/src/routing/filters/exception-filter.js +0 -28
  144. package/commonjs/src/routing/index.js +0 -25
  145. package/commonjs/src/routing/middleware/http-access-log.middleware.js +0 -47
  146. package/commonjs/src/routing/middleware/middleware.js +0 -20
  147. package/commonjs/src/routing/middleware/request-id.js +0 -30
  148. package/commonjs/src/routing/path.util.js +0 -51
  149. package/commonjs/src/routing/pipes/index.js +0 -18
  150. package/commonjs/src/routing/pipes/pipes.js +0 -145
  151. package/commonjs/src/routing/services/index.js +0 -18
  152. package/commonjs/src/routing/services/route-argument-resolver.js +0 -77
  153. package/commonjs/src/routing/services/route-registry.js +0 -194
  154. package/commonjs/src/routing/services/router.js +0 -158
  155. package/commonjs/src/sse/index.js +0 -26
  156. package/commonjs/src/sse/sse.decorator.js +0 -42
  157. package/commonjs/src/sse/sse.encoder.js +0 -73
  158. package/commonjs/src/sse/sse.types.js +0 -36
  159. package/commonjs/src/sse/sse.wire.js +0 -40
  160. package/commonjs/src/testing/boot-module.js +0 -38
  161. package/commonjs/src/testing/index.js +0 -20
  162. package/commonjs/src/testing/sse-reader.js +0 -98
  163. package/es6/src/app/app.js +0 -148
  164. package/es6/src/app/index.js +0 -2
  165. package/es6/src/app/module.js +0 -7
  166. package/es6/src/auth/ability.js +0 -45
  167. package/es6/src/auth/auth.config.js +0 -19
  168. package/es6/src/auth/auth.extensions.js +0 -83
  169. package/es6/src/auth/auth.types.js +0 -35
  170. package/es6/src/auth/casl-authorization.service.js +0 -40
  171. package/es6/src/auth/index.js +0 -6
  172. package/es6/src/auth/principal-provider.js +0 -14
  173. package/es6/src/auth/safe-outbound-url.js +0 -99
  174. package/es6/src/auth/token-service.js +0 -141
  175. package/es6/src/builder/builder.js +0 -85
  176. package/es6/src/builder/index.js +0 -1
  177. package/es6/src/health/health.controller.js +0 -65
  178. package/es6/src/health/health.extensions.js +0 -40
  179. package/es6/src/health/index.js +0 -4
  180. package/es6/src/health/readiness.service.js +0 -57
  181. package/es6/src/health/readiness.types.js +0 -4
  182. package/es6/src/hosting/hosted-service-host.js +0 -81
  183. package/es6/src/hosting/hosted-service.js +0 -8
  184. package/es6/src/hosting/index.js +0 -2
  185. package/es6/src/http/http.compression.js +0 -9
  186. package/es6/src/http/http.extensions.js +0 -259
  187. package/es6/src/http/http.options.js +0 -16
  188. package/es6/src/http/http.options.store.js +0 -13
  189. package/es6/src/http/http.security.js +0 -9
  190. package/es6/src/http/http.static.js +0 -224
  191. package/es6/src/http/index.js +0 -5
  192. package/es6/src/openapi/index.js +0 -3
  193. package/es6/src/openapi/openapi.generator.js +0 -82
  194. package/es6/src/openapi/openapi.types.js +0 -1
  195. package/es6/src/openapi/request-schema.js +0 -160
  196. package/es6/src/openapi/request-validator.js +0 -71
  197. package/es6/src/providers/fastify.provider.js +0 -376
  198. package/es6/src/providers/index.js +0 -1
  199. package/es6/src/routing/anvil.types.js +0 -57
  200. package/es6/src/routing/decorators/argument.decorator.js +0 -28
  201. package/es6/src/routing/decorators/auth.decorator.js +0 -58
  202. package/es6/src/routing/decorators/controller.decorator.js +0 -6
  203. package/es6/src/routing/decorators/field.decorator.js +0 -15
  204. package/es6/src/routing/decorators/index.js +0 -7
  205. package/es6/src/routing/decorators/request.decorator.js +0 -24
  206. package/es6/src/routing/decorators/response.decorator.js +0 -16
  207. package/es6/src/routing/decorators/route.decorator.js +0 -37
  208. package/es6/src/routing/filters/exception-filter-host.js +0 -127
  209. package/es6/src/routing/filters/exception-filter.js +0 -10
  210. package/es6/src/routing/index.js +0 -8
  211. package/es6/src/routing/middleware/http-access-log.middleware.js +0 -37
  212. package/es6/src/routing/middleware/middleware.js +0 -10
  213. package/es6/src/routing/middleware/request-id.js +0 -14
  214. package/es6/src/routing/path.util.js +0 -33
  215. package/es6/src/routing/pipes/index.js +0 -1
  216. package/es6/src/routing/pipes/pipes.js +0 -118
  217. package/es6/src/routing/services/index.js +0 -1
  218. package/es6/src/routing/services/route-argument-resolver.js +0 -67
  219. package/es6/src/routing/services/route-registry.js +0 -184
  220. package/es6/src/routing/services/router.js +0 -148
  221. package/es6/src/sse/index.js +0 -2
  222. package/es6/src/sse/sse.decorator.js +0 -31
  223. package/es6/src/sse/sse.encoder.js +0 -67
  224. package/es6/src/sse/sse.types.js +0 -22
  225. package/es6/src/sse/sse.wire.js +0 -30
  226. package/es6/src/testing/boot-module.js +0 -35
  227. package/es6/src/testing/index.js +0 -2
  228. package/es6/src/testing/sse-reader.js +0 -91
  229. package/types/src/app/app.d.ts +0 -41
  230. package/types/src/app/module.d.ts +0 -15
  231. package/types/src/auth/ability.d.ts +0 -19
  232. package/types/src/auth/auth.config.d.ts +0 -28
  233. package/types/src/auth/auth.extensions.d.ts +0 -53
  234. package/types/src/auth/auth.types.d.ts +0 -73
  235. package/types/src/auth/casl-authorization.service.d.ts +0 -28
  236. package/types/src/auth/safe-outbound-url.d.ts +0 -9
  237. package/types/src/auth/token-service.d.ts +0 -31
  238. package/types/src/builder/builder.d.ts +0 -36
  239. package/types/src/const.d.ts +0 -32
  240. package/types/src/health/health.controller.d.ts +0 -16
  241. package/types/src/health/health.extensions.d.ts +0 -31
  242. package/types/src/health/readiness.service.d.ts +0 -9
  243. package/types/src/hosting/hosted-service-host.d.ts +0 -37
  244. package/types/src/hosting/hosted-service.d.ts +0 -31
  245. package/types/src/http/http.compression.d.ts +0 -32
  246. package/types/src/http/http.extensions.d.ts +0 -79
  247. package/types/src/http/http.options.d.ts +0 -39
  248. package/types/src/http/http.static.d.ts +0 -160
  249. package/types/src/index.d.ts +0 -10
  250. package/types/src/openapi/index.d.ts +0 -6
  251. package/types/src/openapi/openapi.generator.d.ts +0 -6
  252. package/types/src/openapi/openapi.types.d.ts +0 -58
  253. package/types/src/openapi/request-schema.d.ts +0 -21
  254. package/types/src/openapi/request-validator.d.ts +0 -9
  255. package/types/src/providers/fastify.provider.d.ts +0 -56
  256. package/types/src/routing/anvil.types.d.ts +0 -119
  257. package/types/src/routing/decorators/argument.decorator.d.ts +0 -11
  258. package/types/src/routing/decorators/auth.decorator.d.ts +0 -30
  259. package/types/src/routing/decorators/controller.decorator.d.ts +0 -3
  260. package/types/src/routing/decorators/field.decorator.d.ts +0 -2
  261. package/types/src/routing/decorators/request.decorator.d.ts +0 -8
  262. package/types/src/routing/decorators/response.decorator.d.ts +0 -4
  263. package/types/src/routing/decorators/route.decorator.d.ts +0 -7
  264. package/types/src/routing/filters/exception-filter-host.d.ts +0 -19
  265. package/types/src/routing/filters/exception-filter.d.ts +0 -16
  266. package/types/src/routing/middleware/http-access-log.middleware.d.ts +0 -8
  267. package/types/src/routing/middleware/middleware.d.ts +0 -10
  268. package/types/src/routing/middleware/request-id.d.ts +0 -6
  269. package/types/src/routing/path.util.d.ts +0 -9
  270. package/types/src/routing/pipes/pipes.d.ts +0 -21
  271. package/types/src/routing/services/route-argument-resolver.d.ts +0 -10
  272. package/types/src/routing/services/route-registry.d.ts +0 -20
  273. package/types/src/routing/services/router.d.ts +0 -22
  274. package/types/src/sse/sse.decorator.d.ts +0 -17
  275. package/types/src/sse/sse.encoder.d.ts +0 -16
  276. package/types/src/sse/sse.types.d.ts +0 -37
  277. package/types/src/sse/sse.wire.d.ts +0 -9
  278. package/types/src/testing/boot-module.d.ts +0 -34
  279. package/types/src/testing/sse-reader.d.ts +0 -29
  280. /package/{types/src/app/index.d.ts → src/app/index.ts} +0 -0
  281. /package/{types/src/auth/index.d.ts → src/auth/index.ts} +0 -0
  282. /package/{types/src/builder/index.d.ts → src/builder/index.ts} +0 -0
  283. /package/{types/src/health/index.d.ts → src/health/index.ts} +0 -0
  284. /package/{types/src/hosting/index.d.ts → src/hosting/index.ts} +0 -0
  285. /package/{types/src/http/index.d.ts → src/http/index.ts} +0 -0
  286. /package/{types/src/providers/index.d.ts → src/providers/index.ts} +0 -0
  287. /package/{types/src/routing/decorators/index.d.ts → src/routing/decorators/index.ts} +0 -0
  288. /package/{types/src/routing/index.d.ts → src/routing/index.ts} +0 -0
  289. /package/{types/src/routing/pipes/index.d.ts → src/routing/pipes/index.ts} +0 -0
  290. /package/{types/src/routing/services/index.d.ts → src/routing/services/index.ts} +0 -0
  291. /package/{types/src/sse/index.d.ts → src/sse/index.ts} +0 -0
  292. /package/{types/src/testing/index.d.ts → src/testing/index.ts} +0 -0
@@ -1,259 +0,0 @@
1
- function _ts_decorate(decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- 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;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- }
7
- function _ts_metadata(k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- }
10
- import { extension } from "@decohere/core/extensibility";
11
- import { scribe } from "@decohere/scribe";
12
- import { PrincipalProvider } from "../auth/principal-provider.js";
13
- import { Builder } from "../builder/builder.js";
14
- import { ExceptionFilterHostToken, HttpOptionsToken, HttpProviderToken, IPrincipalProviderToken, RouteRegistryToken, RouterToken } from "../const.js";
15
- import { ExceptionFilterHost } from "../routing/filters/exception-filter-host.js";
16
- import { HttpAccessLogMiddleware } from "../routing/middleware/http-access-log.middleware.js";
17
- import { RouteRegistry } from "../routing/services/route-registry.js";
18
- import { Router } from "../routing/services/router.js";
19
- import { getOrCreateHttpOptions } from "./http.options.store.js";
20
- import { staticFiles } from "./http.static.js";
21
- const httpProviderStore = new WeakMap();
22
- const controllersStore = new WeakMap();
23
- export class BuilderExtensions {
24
- static withHttpProvider(builder, type) {
25
- httpProviderStore.set(builder, type);
26
- const httpOptions = getOrCreateHttpOptions(builder);
27
- builder.withServices((containerBuilder)=>{
28
- const logger = scribe.logger("BuilderExtensions");
29
- logger.trace("Configuring Http Provider");
30
- const http = httpProviderStore.get(builder);
31
- if (!http) {
32
- return;
33
- }
34
- containerBuilder.registerSingleton(HttpOptionsToken, httpOptions);
35
- containerBuilder.registerSingleton(HttpProviderToken, http);
36
- containerBuilder.registerSingleton(RouterToken, Router);
37
- containerBuilder.registerSingleton(RouteRegistryToken, RouteRegistry);
38
- containerBuilder.registerSingleton(ExceptionFilterHostToken, ExceptionFilterHost);
39
- containerBuilder.registerRequestScoped(IPrincipalProviderToken, PrincipalProvider);
40
- for (const middlewareType of httpOptions.middlewareTypes){
41
- containerBuilder.registerSingleton(middlewareType);
42
- }
43
- for (const filterType of httpOptions.filterTypes){
44
- containerBuilder.registerSingleton(filterType);
45
- }
46
- const controllers = controllersStore.get(builder) || [];
47
- for (const controllerFn of controllers){
48
- containerBuilder.registerRequestScoped(controllerFn);
49
- }
50
- });
51
- builder.registerPostBuildStep((container)=>{
52
- const logger = scribe.logger("BuilderExtensions");
53
- const registry = container.resolve(RouteRegistryToken);
54
- const controllers = controllersStore.get(builder) || [];
55
- for (const controllerFn of controllers){
56
- logger.trace(`Add routes from ${controllerFn.name}`);
57
- registry.addController(controllerFn);
58
- }
59
- });
60
- return builder;
61
- }
62
- static withHttp(builder, type, options) {
63
- const accessLog = options?.accessLog !== false;
64
- if (accessLog) {
65
- const httpOptions = getOrCreateHttpOptions(builder);
66
- if (!httpOptions.middlewareTypes.includes(HttpAccessLogMiddleware)) {
67
- httpOptions.middlewareTypes = [
68
- ...httpOptions.middlewareTypes,
69
- HttpAccessLogMiddleware
70
- ];
71
- }
72
- }
73
- return BuilderExtensions.withHttpProvider(builder, type);
74
- }
75
- static withControllers(builder, ...controllers) {
76
- const existing = controllersStore.get(builder) || [];
77
- controllersStore.set(builder, [
78
- ...existing,
79
- ...controllers
80
- ]);
81
- return builder;
82
- }
83
- static withGlobalPrefix(builder, prefix) {
84
- getOrCreateHttpOptions(builder).globalPrefix = prefix;
85
- return builder;
86
- }
87
- static withCors(builder, options) {
88
- getOrCreateHttpOptions(builder).cors = options;
89
- return builder;
90
- }
91
- static withHelmet(builder, options = {}) {
92
- getOrCreateHttpOptions(builder).helmet = options;
93
- return builder;
94
- }
95
- static withRateLimit(builder, options = {}) {
96
- getOrCreateHttpOptions(builder).rateLimit = options;
97
- return builder;
98
- }
99
- static withCompression(builder, options = {}) {
100
- getOrCreateHttpOptions(builder).compression = options;
101
- return builder;
102
- }
103
- static withBodyLimit(builder, bytes) {
104
- getOrCreateHttpOptions(builder).bodyLimit = bytes;
105
- return builder;
106
- }
107
- static withMiddleware(builder, ...middlewares) {
108
- const httpOptions = getOrCreateHttpOptions(builder);
109
- httpOptions.middlewareTypes = [
110
- ...httpOptions.middlewareTypes,
111
- ...middlewares
112
- ];
113
- return builder;
114
- }
115
- static withExceptionFilters(builder, ...filters) {
116
- const httpOptions = getOrCreateHttpOptions(builder);
117
- httpOptions.filterTypes = [
118
- ...httpOptions.filterTypes,
119
- ...filters
120
- ];
121
- return builder;
122
- }
123
- static withOpenApi(builder, options) {
124
- getOrCreateHttpOptions(builder).openapi = {
125
- validateRequests: true,
126
- path: "/openapi.json",
127
- ...options
128
- };
129
- return builder;
130
- }
131
- static withStatic(builder, prefix, directory, options) {
132
- const httpOptions = getOrCreateHttpOptions(builder);
133
- httpOptions.statics = [
134
- ...httpOptions.statics,
135
- staticFiles.toMount(prefix, directory, options)
136
- ];
137
- return builder;
138
- }
139
- }
140
- _ts_decorate([
141
- extension(Builder),
142
- _ts_metadata("design:type", Function),
143
- _ts_metadata("design:paramtypes", [
144
- typeof Builder === "undefined" ? Object : Builder,
145
- typeof Thttp === "undefined" ? Object : Thttp
146
- ]),
147
- _ts_metadata("design:returntype", void 0)
148
- ], BuilderExtensions, "withHttpProvider", null);
149
- _ts_decorate([
150
- extension(Builder),
151
- _ts_metadata("design:type", Function),
152
- _ts_metadata("design:paramtypes", [
153
- typeof Builder === "undefined" ? Object : Builder,
154
- typeof Thttp === "undefined" ? Object : Thttp,
155
- typeof WithHttpOptions === "undefined" ? Object : WithHttpOptions
156
- ]),
157
- _ts_metadata("design:returntype", void 0)
158
- ], BuilderExtensions, "withHttp", null);
159
- _ts_decorate([
160
- extension(Builder),
161
- _ts_metadata("design:type", Function),
162
- _ts_metadata("design:paramtypes", [
163
- typeof Builder === "undefined" ? Object : Builder,
164
- Array
165
- ]),
166
- _ts_metadata("design:returntype", void 0)
167
- ], BuilderExtensions, "withControllers", null);
168
- _ts_decorate([
169
- extension(Builder),
170
- _ts_metadata("design:type", Function),
171
- _ts_metadata("design:paramtypes", [
172
- typeof Builder === "undefined" ? Object : Builder,
173
- String
174
- ]),
175
- _ts_metadata("design:returntype", void 0)
176
- ], BuilderExtensions, "withGlobalPrefix", null);
177
- _ts_decorate([
178
- extension(Builder),
179
- _ts_metadata("design:type", Function),
180
- _ts_metadata("design:paramtypes", [
181
- typeof Builder === "undefined" ? Object : Builder,
182
- typeof CorsOptions === "undefined" ? Object : CorsOptions
183
- ]),
184
- _ts_metadata("design:returntype", void 0)
185
- ], BuilderExtensions, "withCors", null);
186
- _ts_decorate([
187
- extension(Builder),
188
- _ts_metadata("design:type", Function),
189
- _ts_metadata("design:paramtypes", [
190
- typeof Builder === "undefined" ? Object : Builder,
191
- typeof HelmetOptions === "undefined" ? Object : HelmetOptions
192
- ]),
193
- _ts_metadata("design:returntype", void 0)
194
- ], BuilderExtensions, "withHelmet", null);
195
- _ts_decorate([
196
- extension(Builder),
197
- _ts_metadata("design:type", Function),
198
- _ts_metadata("design:paramtypes", [
199
- typeof Builder === "undefined" ? Object : Builder,
200
- typeof RateLimitOptions === "undefined" ? Object : RateLimitOptions
201
- ]),
202
- _ts_metadata("design:returntype", void 0)
203
- ], BuilderExtensions, "withRateLimit", null);
204
- _ts_decorate([
205
- extension(Builder),
206
- _ts_metadata("design:type", Function),
207
- _ts_metadata("design:paramtypes", [
208
- typeof Builder === "undefined" ? Object : Builder,
209
- typeof CompressionOptions === "undefined" ? Object : CompressionOptions
210
- ]),
211
- _ts_metadata("design:returntype", void 0)
212
- ], BuilderExtensions, "withCompression", null);
213
- _ts_decorate([
214
- extension(Builder),
215
- _ts_metadata("design:type", Function),
216
- _ts_metadata("design:paramtypes", [
217
- typeof Builder === "undefined" ? Object : Builder,
218
- Number
219
- ]),
220
- _ts_metadata("design:returntype", void 0)
221
- ], BuilderExtensions, "withBodyLimit", null);
222
- _ts_decorate([
223
- extension(Builder),
224
- _ts_metadata("design:type", Function),
225
- _ts_metadata("design:paramtypes", [
226
- typeof Builder === "undefined" ? Object : Builder,
227
- Array
228
- ]),
229
- _ts_metadata("design:returntype", void 0)
230
- ], BuilderExtensions, "withMiddleware", null);
231
- _ts_decorate([
232
- extension(Builder),
233
- _ts_metadata("design:type", Function),
234
- _ts_metadata("design:paramtypes", [
235
- typeof Builder === "undefined" ? Object : Builder,
236
- Array
237
- ]),
238
- _ts_metadata("design:returntype", void 0)
239
- ], BuilderExtensions, "withExceptionFilters", null);
240
- _ts_decorate([
241
- extension(Builder),
242
- _ts_metadata("design:type", Function),
243
- _ts_metadata("design:paramtypes", [
244
- typeof Builder === "undefined" ? Object : Builder,
245
- typeof OpenApiOptions === "undefined" ? Object : OpenApiOptions
246
- ]),
247
- _ts_metadata("design:returntype", void 0)
248
- ], BuilderExtensions, "withOpenApi", null);
249
- _ts_decorate([
250
- extension(Builder),
251
- _ts_metadata("design:type", Function),
252
- _ts_metadata("design:paramtypes", [
253
- typeof Builder === "undefined" ? Object : Builder,
254
- String,
255
- String,
256
- typeof StaticOptions === "undefined" ? Object : StaticOptions
257
- ]),
258
- _ts_metadata("design:returntype", void 0)
259
- ], BuilderExtensions, "withStatic", null);
@@ -1,16 +0,0 @@
1
- /** App-level HTTP options set via builder extensions (`withCors`, `withGlobalPrefix`, …). */ export class HttpOptions {
2
- globalPrefix = "";
3
- /**
4
- * Controllers put under the global prefix although they declare `globalPrefix: false`
5
- * (`withHealth({ underGlobalPrefix: true })`).
6
- */ underGlobalPrefix = new Set();
7
- cors;
8
- openapi;
9
- /** `undefined` = helmet on with defaults; `false` = off; object = plugin options. */ helmet;
10
- /** `undefined` = rate-limit on with defaults; `false` = off; object = plugin options. */ rateLimit;
11
- /** `undefined` = compression on with defaults; `false` = off; object = options. See `withCompression`. */ compression;
12
- /** Request body size limit in bytes; `undefined` uses the 1 MiB default. */ bodyLimit;
13
- /** Built UIs served from this API, see `withStatic`. */ statics = [];
14
- middlewareTypes = [];
15
- filterTypes = [];
16
- }
@@ -1,13 +0,0 @@
1
- import { HttpOptions } from "./http.options.js";
2
- const httpOptionsStore = new WeakMap();
3
- /**
4
- * The {@link HttpOptions} a builder collects through its extensions. Internal: lets extensions
5
- * outside `http.extensions.ts` (`withHealth`) set an option without a public builder method.
6
- */ export function getOrCreateHttpOptions(builder) {
7
- let options = httpOptionsStore.get(builder);
8
- if (options == null) {
9
- options = new HttpOptions();
10
- httpOptionsStore.set(builder, options);
11
- }
12
- return options;
13
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Default HTTP security settings applied by {@link FastifyProvider} when
3
- * `withHttpProvider` is used. Override via `withHelmet` / `withRateLimit` /
4
- * `withBodyLimit` (pass `false` to disable helmet or rate-limit).
5
- */ /** Fastify body size limit (bytes). Matches Fastify's built-in default, made explicit and overridable. */ export const DEFAULT_HTTP_BODY_LIMIT = 1_048_576;
6
- /** Global request rate limit applied unless disabled or customized. */ export const DEFAULT_HTTP_RATE_LIMIT = {
7
- max: 100,
8
- timeWindow: "1 minute"
9
- };
@@ -1,224 +0,0 @@
1
- import path from "node:path";
2
- import picomatch from "picomatch";
3
- import { isDevelopmentNodeEnv } from "../auth/auth.types.js";
4
- /**
5
- * Serving a module's built UI from its API (`builder.withStatic`). Everything here is
6
- * provider-neutral: the options, the caching rules and the missing-directory policy.
7
- * Only the HTTP provider knows how to put files on the wire. See ADR 0007.
8
- */ /** Cache header for files whose name carries a content hash. The name changes when the content does. */ export const STATIC_IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
9
- /** Cache header for files that must be revalidated on every use (the entry points of a UI). */ export const STATIC_NO_CACHE_CONTROL = "no-cache";
10
- /** Cache header for every other file: cacheable, but always revalidated (ETag / Last-Modified). */ export const STATIC_DEFAULT_CACHE_CONTROL = "public, max-age=0, must-revalidate";
11
- /**
12
- * The entry points of a UI. `index.html` names the hashed bundles, and a module-federation host
13
- * loads `remoteEntry.js` by a fixed name to find the current remote, so neither can be cached.
14
- */ export const STATIC_DEFAULT_NO_CACHE = [
15
- "index.html",
16
- "remoteEntry.js"
17
- ];
18
- /**
19
- * A build tool's hashed file name: `index-DiwrgTda.js`, `chunk.3f9a8c1b.css`, `app-abc123de.js.map`.
20
- * The hash is 8 or more letters, digits or `_` after a `-` or `.`, and holds a digit or a lowercase
21
- * letter followed by an uppercase one. Plain words (`logo-background.png`) are not hashes.
22
- */ export const STATIC_DEFAULT_IMMUTABLE = /[.-](?=[A-Za-z0-9_]*(?:\d|[a-z][A-Z]))[A-Za-z0-9_]{8,}\.[A-Za-z0-9]+(?:\.map)?$/;
23
- /** `"ui"`, `"/ui"` and `"/ui/"` all mean `/ui/`; `"/"` is the root. Refuses an empty prefix. */ function normalizePrefix(prefix) {
24
- const segments = prefix.split("/").filter((segment)=>segment !== "");
25
- if (segments.length === 0) {
26
- if (prefix.trim() === "") {
27
- throw new Error('withStatic needs a prefix, such as "/ui/" or "/" for the root.');
28
- }
29
- return "/";
30
- }
31
- if (segments.some((segment)=>segment === "." || segment === ".." || /[*:?]/.test(segment))) {
32
- throw new Error(`withStatic prefix "${prefix}" must be plain path segments, such as "/ui/".`);
33
- }
34
- return `/${segments.join("/")}/`;
35
- }
36
- function toMount(prefix, directory, options = {}) {
37
- if (directory.trim() === "") {
38
- throw new Error(`withStatic("${prefix}") needs the directory that holds the built files.`);
39
- }
40
- return {
41
- prefix: normalizePrefix(prefix),
42
- directory,
43
- options
44
- };
45
- }
46
- /**
47
- * Checks every mount at start. Returns the ones that can be served; a missing directory fails or
48
- * warns according to the mount's `onMissingDirectory`. Two mounts on one prefix always fail.
49
- */ async function resolve(mounts, env) {
50
- const cwd = env.cwd ?? process.cwd();
51
- const resolved = [];
52
- const seen = new Set();
53
- for (const mount of mounts){
54
- if (seen.has(mount.prefix)) {
55
- throw new Error(`withStatic: ${mount.prefix} is mounted twice.`);
56
- }
57
- seen.add(mount.prefix);
58
- const root = path.resolve(cwd, mount.directory);
59
- if (!await env.directoryExists(root)) {
60
- const policy = mount.options.onMissingDirectory ?? (isDevelopmentNodeEnv(env.nodeEnv) ? "warn" : "fail");
61
- const message = `withStatic("${mount.prefix}", "${mount.directory}"): ${root} does not exist. ` + "Build the UI first, or run the app from the folder that holds it.";
62
- if (policy === "fail") {
63
- throw new Error(message);
64
- }
65
- env.warn(`${message} ${mount.prefix} will answer 404 until it is built and the app restarts.`);
66
- continue;
67
- }
68
- const options = mount.options;
69
- resolved.push({
70
- prefix: mount.prefix,
71
- root,
72
- spaFallback: options.spaFallback ?? true,
73
- index: options.index ?? "index.html",
74
- noCache: options.noCache ?? STATIC_DEFAULT_NO_CACHE,
75
- immutable: options.immutable ?? STATIC_DEFAULT_IMMUTABLE,
76
- cacheControl: options.cacheControl ?? STATIC_DEFAULT_CACHE_CONTROL,
77
- exclude: options.exclude ?? []
78
- });
79
- }
80
- return resolved;
81
- }
82
- /** `Cache-Control` for a file, given its path relative to the mount's directory. */ function cacheControlFor(mount, relativePath) {
83
- const posix = relativePath.split(path.sep).join("/");
84
- const name = path.posix.basename(posix);
85
- if (mount.noCache.some((entry)=>entry === name || entry === posix)) {
86
- return STATIC_NO_CACHE_CONTROL;
87
- }
88
- if (mount.immutable !== false && mount.immutable.test(posix)) {
89
- return STATIC_IMMUTABLE_CACHE_CONTROL;
90
- }
91
- return mount.cacheControl;
92
- }
93
- /**
94
- * Does this path look like a file: an extension on the last segment, or a dotfile anywhere?
95
- * Then a miss is a real 404, not a client-side route.
96
- */ function looksLikeFile(pathname) {
97
- const segments = pathname.split("/").filter((segment)=>segment !== "");
98
- if (segments.some((segment)=>segment.startsWith("."))) {
99
- return true;
100
- }
101
- const last = pathname.endsWith("/") ? undefined : segments.at(-1);
102
- return last?.includes(".") === true;
103
- }
104
- /** The request path as the mount sees it: no query, decoded, repeated slashes collapsed. */ function normalizePathname(url) {
105
- const raw = url.split("?")[0] ?? "";
106
- let decoded = raw;
107
- try {
108
- decoded = decodeURIComponent(raw);
109
- } catch {
110
- // Keep the raw text: a malformed escape is matched as written.
111
- }
112
- return decoded.replace(/\/{2,}/g, "/");
113
- }
114
- /** Builds the test for a mount's `exclude` patterns. Matches on the normalised path. */ function excluder(patterns) {
115
- if (patterns.length === 0) {
116
- return ()=>false;
117
- }
118
- const matches = picomatch([
119
- ...patterns
120
- ], {
121
- dot: true
122
- });
123
- return (pathname)=>matches(pathname);
124
- }
125
- /**
126
- * The first path segment of every registered route, for {@link isUnderRoute}. A segment that is a
127
- * parameter or wildcard (`:id`, `*`) says nothing about the path and is skipped.
128
- */ function routeSegments(routePaths) {
129
- const segments = new Set();
130
- for (const routePath of routePaths){
131
- const first = routePath.split("/").find((segment)=>segment !== "");
132
- if (first != null && !/[:*]/.test(first)) {
133
- segments.add(first);
134
- }
135
- }
136
- return segments;
137
- }
138
- /**
139
- * Is this path under one of the app's own routes? True when its first segment is the first
140
- * segment of a registered route: with a controller route `/lp/portfolio`, `/lp/portfolo` and
141
- * `/lp/anything/else` belong to the API and keep the JSON 404, while `/lpx` does not.
142
- */ function isUnderRoute(pathname, segments) {
143
- const first = pathname.split("/").find((segment)=>segment !== "");
144
- return first != null && segments.has(first);
145
- }
146
- /** Is `pathname` the path `base` or below it? `/api` holds `/api` and `/api/x`, not `/apiary`. */ function isWithin(pathname, base) {
147
- const trimmed = base.replace(/\/+$/, "");
148
- return pathname === trimmed || pathname.startsWith(`${trimmed}/`);
149
- }
150
- /**
151
- * The literal start of a route path, up to its first parameter or wildcard: `/webhooks/:id` gives
152
- * `/webhooks`, `/:id` gives `""`.
153
- */ function staticStem(routePath) {
154
- const stem = [];
155
- for (const segment of routePath.split("/")){
156
- if (segment.startsWith(":") || segment.includes("*")) {
157
- break;
158
- }
159
- if (segment !== "") {
160
- stem.push(segment);
161
- }
162
- }
163
- return stem.length === 0 ? "" : `/${stem.join("/")}`;
164
- }
165
- /**
166
- * What the fallback treats as the API, as a test on the normalised path. With a global prefix it
167
- * is the prefix, the OpenAPI path and every route left outside the prefix
168
- * (`@Controller({ globalPrefix: false })`, such as `/health`), each with the paths below it, so a
169
- * client route may share a first segment with a controller. Without a prefix it is
170
- * {@link isUnderRoute} (the first segment of every registered route), the safe guess when nothing
171
- * says where the API lives.
172
- */ function apiBoundary(boundary) {
173
- if (boundary.globalPrefix === "") {
174
- const segments = routeSegments([
175
- ...boundary.routePaths,
176
- ...boundary.openApiPath == null ? [] : [
177
- boundary.openApiPath
178
- ]
179
- ]);
180
- return (pathname)=>isUnderRoute(pathname, segments);
181
- }
182
- const outside = [
183
- ...boundary.routePaths
184
- ].filter((routePath)=>!isWithin(routePath, boundary.globalPrefix)).map(staticStem).filter((stem)=>stem !== "");
185
- const bases = [
186
- boundary.globalPrefix,
187
- boundary.openApiPath,
188
- ...outside
189
- ].filter((base)=>base != null);
190
- return (pathname)=>bases.some((base)=>isWithin(pathname, base));
191
- }
192
- /** Does the `Accept` header ask for HTML (a browser navigation)? `text/html;q=0` does not. */ function acceptsHtml(accept) {
193
- if (accept == null) {
194
- return false;
195
- }
196
- return accept.split(",").some((entry)=>{
197
- const [type = "", ...params] = entry.split(";").map((part)=>part.trim().toLowerCase());
198
- if (type !== "text/html") {
199
- return false;
200
- }
201
- const quality = params.find((param)=>param.startsWith("q="));
202
- return quality == null || Number.parseFloat(quality.slice(2)) > 0;
203
- });
204
- }
205
- /**
206
- * Should an unknown path get the app's `index.html`? Only a browser navigation: GET or HEAD, no
207
- * file extension and no dotfile in the path, an `Accept` that includes `text/html`, and not under
208
- * the API (see {@link apiBoundary}). Everything else keeps the normal JSON 404.
209
- */ function shouldFallBack(request, belongsToApi) {
210
- return (request.method === "GET" || request.method === "HEAD") && acceptsHtml(request.accept) && !looksLikeFile(request.pathname) && !belongsToApi(request.pathname);
211
- }
212
- export const staticFiles = {
213
- toMount,
214
- resolve,
215
- cacheControlFor,
216
- looksLikeFile,
217
- normalizePathname,
218
- excluder,
219
- routeSegments,
220
- isUnderRoute,
221
- apiBoundary,
222
- acceptsHtml,
223
- shouldFallBack
224
- };
@@ -1,5 +0,0 @@
1
- export * from "./http.compression.js";
2
- export * from "./http.extensions.js";
3
- export * from "./http.options.js";
4
- export * from "./http.security.js";
5
- export * from "./http.static.js";
@@ -1,3 +0,0 @@
1
- export { generateOpenApiDocument, resolveOpenApiPath, toOpenApiPath } from "./openapi.generator.js";
2
- export { buildRouteRequestSchemas, mergeObjectSchemas, objectArgToParts, pathParamsToSchema, typeToSchema } from "./request-schema.js";
3
- export { ValidationError, validateRequest } from "./request-validator.js";
@@ -1,82 +0,0 @@
1
- import { buildRouteRequestSchemas } from "./request-schema.js";
2
- const DEFAULT_SPEC_PATH = "/openapi.json";
3
- export function resolveOpenApiPath(options) {
4
- const path = options.path?.trim() || DEFAULT_SPEC_PATH;
5
- return path.startsWith("/") ? path : `/${path}`;
6
- }
7
- /** Convert Fastify-style `:id` path params to OpenAPI `{id}`. */ export function toOpenApiPath(fastifyPath) {
8
- return fastifyPath.replace(/:([A-Za-z_][\w]*)/g, "{$1}");
9
- }
10
- export function generateOpenApiDocument(registry, options) {
11
- const paths = {};
12
- for (const route of registry.routes){
13
- const path = toOpenApiPath(route.path);
14
- const method = route.method.toLowerCase();
15
- let pathItem = paths[path];
16
- if (pathItem == null) {
17
- pathItem = {};
18
- paths[path] = pathItem;
19
- }
20
- pathItem[method] = buildOperation(route);
21
- }
22
- const document = {
23
- openapi: "3.0.3",
24
- info: options.info,
25
- paths
26
- };
27
- if (options.servers?.length) {
28
- document.servers = options.servers;
29
- }
30
- return document;
31
- }
32
- function buildOperation(route) {
33
- const { queryParams, pathParams, body: bodySchema } = buildRouteRequestSchemas(route);
34
- const parameters = [
35
- ...queryParams,
36
- ...pathParams
37
- ];
38
- const status = String(route.httpCode ?? 200);
39
- const operation = {
40
- operationId: `${route.controller.name}.${route.handler}`,
41
- tags: [
42
- route.controller.name
43
- ],
44
- responses: {
45
- [status]: route.sse ? {
46
- description: "Server-sent event stream",
47
- content: {
48
- "text/event-stream": {
49
- schema: {
50
- type: "string"
51
- }
52
- }
53
- }
54
- } : {
55
- description: "Successful response"
56
- }
57
- }
58
- };
59
- if (route.routeArgs?.some((arg)=>arg.argumentLocation === "lastEventId")) {
60
- parameters.push({
61
- name: "Last-Event-ID",
62
- in: "header",
63
- schema: {
64
- type: "string"
65
- }
66
- });
67
- }
68
- if (parameters.length > 0) {
69
- operation.parameters = parameters;
70
- }
71
- if (bodySchema != null) {
72
- operation.requestBody = {
73
- required: true,
74
- content: {
75
- "application/json": {
76
- schema: bodySchema
77
- }
78
- }
79
- };
80
- }
81
- return operation;
82
- }
@@ -1 +0,0 @@
1
- export { };