@adonisjs/http-server 6.8.2-4 → 6.8.2-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 (155) hide show
  1. package/LICENSE.md +1 -1
  2. package/build/factories/http_context.d.ts +1 -0
  3. package/build/factories/http_context.d.ts.map +1 -0
  4. package/build/factories/main.d.ts +1 -0
  5. package/build/factories/main.d.ts.map +1 -0
  6. package/build/factories/qs_parser_factory.d.ts +1 -0
  7. package/build/factories/qs_parser_factory.d.ts.map +1 -0
  8. package/build/factories/request.d.ts +1 -0
  9. package/build/factories/request.d.ts.map +1 -0
  10. package/build/factories/response.d.ts +1 -0
  11. package/build/factories/response.d.ts.map +1 -0
  12. package/build/factories/router.d.ts +1 -0
  13. package/build/factories/router.d.ts.map +1 -0
  14. package/build/factories/server_factory.d.ts +1 -0
  15. package/build/factories/server_factory.d.ts.map +1 -0
  16. package/build/index.d.ts +1 -0
  17. package/build/index.d.ts.map +1 -0
  18. package/build/src/cookies/client.d.ts +1 -0
  19. package/build/src/cookies/client.d.ts.map +1 -0
  20. package/build/src/cookies/drivers/encrypted.d.ts +1 -0
  21. package/build/src/cookies/drivers/encrypted.d.ts.map +1 -0
  22. package/build/src/cookies/drivers/plain.d.ts +1 -0
  23. package/build/src/cookies/drivers/plain.d.ts.map +1 -0
  24. package/build/src/cookies/drivers/signed.d.ts +1 -0
  25. package/build/src/cookies/drivers/signed.d.ts.map +1 -0
  26. package/build/src/cookies/parser.d.ts +1 -0
  27. package/build/src/cookies/parser.d.ts.map +1 -0
  28. package/build/src/cookies/serializer.d.ts +1 -0
  29. package/build/src/cookies/serializer.d.ts.map +1 -0
  30. package/build/src/debug.d.ts +1 -0
  31. package/build/src/debug.d.ts.map +1 -0
  32. package/build/src/define_config.d.ts +1 -0
  33. package/build/src/define_config.d.ts.map +1 -0
  34. package/build/src/define_middleware.d.ts +1 -0
  35. package/build/src/define_middleware.d.ts.map +1 -0
  36. package/build/src/exception_handler.d.ts +1 -0
  37. package/build/src/exception_handler.d.ts.map +1 -0
  38. package/build/src/exceptions.d.ts +1 -0
  39. package/build/src/exceptions.d.ts.map +1 -0
  40. package/build/src/helpers.d.ts +1 -0
  41. package/build/src/helpers.d.ts.map +1 -0
  42. package/build/src/http_context/local_storage.d.ts +1 -0
  43. package/build/src/http_context/local_storage.d.ts.map +1 -0
  44. package/build/src/http_context/main.d.ts +1 -0
  45. package/build/src/http_context/main.d.ts.map +1 -0
  46. package/build/src/qs.d.ts +1 -0
  47. package/build/src/qs.d.ts.map +1 -0
  48. package/build/src/redirect.d.ts +1 -0
  49. package/build/src/redirect.d.ts.map +1 -0
  50. package/build/src/request.d.ts +1 -0
  51. package/build/src/request.d.ts.map +1 -0
  52. package/build/src/response.d.ts +1 -0
  53. package/build/src/response.d.ts.map +1 -0
  54. package/build/src/router/brisk.d.ts +1 -0
  55. package/build/src/router/brisk.d.ts.map +1 -0
  56. package/build/src/router/executor.d.ts +1 -0
  57. package/build/src/router/executor.d.ts.map +1 -0
  58. package/build/src/router/factories/use_return_value.d.ts +1 -0
  59. package/build/src/router/factories/use_return_value.d.ts.map +1 -0
  60. package/build/src/router/group.d.ts +1 -0
  61. package/build/src/router/group.d.ts.map +1 -0
  62. package/build/src/router/lookup_store/main.d.ts +1 -0
  63. package/build/src/router/lookup_store/main.d.ts.map +1 -0
  64. package/build/src/router/lookup_store/route_finder.d.ts +1 -0
  65. package/build/src/router/lookup_store/route_finder.d.ts.map +1 -0
  66. package/build/src/router/lookup_store/url_builder.d.ts +1 -0
  67. package/build/src/router/lookup_store/url_builder.d.ts.map +1 -0
  68. package/build/src/router/main.d.ts +1 -0
  69. package/build/src/router/main.d.ts.map +1 -0
  70. package/build/src/router/matchers.d.ts +1 -0
  71. package/build/src/router/matchers.d.ts.map +1 -0
  72. package/build/src/router/parser.d.ts +1 -0
  73. package/build/src/router/parser.d.ts.map +1 -0
  74. package/build/src/router/resource.d.ts +1 -0
  75. package/build/src/router/resource.d.ts.map +1 -0
  76. package/build/src/router/route.d.ts +1 -0
  77. package/build/src/router/route.d.ts.map +1 -0
  78. package/build/src/router/store.d.ts +1 -0
  79. package/build/src/router/store.d.ts.map +1 -0
  80. package/build/src/server/factories/final_handler.d.ts +1 -0
  81. package/build/src/server/factories/final_handler.d.ts.map +1 -0
  82. package/build/src/server/factories/middleware_handler.d.ts +1 -0
  83. package/build/src/server/factories/middleware_handler.d.ts.map +1 -0
  84. package/build/src/server/factories/write_response.d.ts +1 -0
  85. package/build/src/server/factories/write_response.d.ts.map +1 -0
  86. package/build/src/server/main.d.ts +1 -0
  87. package/build/src/server/main.d.ts.map +1 -0
  88. package/build/src/types/base.d.ts +1 -0
  89. package/build/src/types/base.d.ts.map +1 -0
  90. package/build/src/types/main.d.ts +1 -0
  91. package/build/src/types/main.d.ts.map +1 -0
  92. package/build/src/types/middleware.d.ts +1 -0
  93. package/build/src/types/middleware.d.ts.map +1 -0
  94. package/build/src/types/qs.d.ts +1 -0
  95. package/build/src/types/qs.d.ts.map +1 -0
  96. package/build/src/types/request.d.ts +1 -0
  97. package/build/src/types/request.d.ts.map +1 -0
  98. package/build/src/types/response.d.ts +1 -0
  99. package/build/src/types/response.d.ts.map +1 -0
  100. package/build/src/types/route.d.ts +1 -0
  101. package/build/src/types/route.d.ts.map +1 -0
  102. package/build/src/types/server.d.ts +1 -0
  103. package/build/src/types/server.d.ts.map +1 -0
  104. package/factories/http_context.ts +73 -0
  105. package/factories/main.ts +15 -0
  106. package/factories/qs_parser_factory.ts +54 -0
  107. package/factories/request.ts +101 -0
  108. package/factories/response.ts +106 -0
  109. package/factories/router.ts +61 -0
  110. package/factories/server_factory.ts +94 -0
  111. package/index.ts +23 -0
  112. package/package.json +27 -23
  113. package/src/cookies/client.ts +98 -0
  114. package/src/cookies/drivers/encrypted.ts +42 -0
  115. package/src/cookies/drivers/plain.ts +37 -0
  116. package/src/cookies/drivers/signed.ts +42 -0
  117. package/src/cookies/parser.ts +196 -0
  118. package/src/cookies/serializer.ts +98 -0
  119. package/src/debug.ts +11 -0
  120. package/src/define_config.ts +56 -0
  121. package/src/define_middleware.ts +61 -0
  122. package/src/exception_handler.ts +290 -0
  123. package/src/exceptions.ts +55 -0
  124. package/src/helpers.ts +108 -0
  125. package/src/http_context/local_storage.ts +50 -0
  126. package/src/http_context/main.ts +126 -0
  127. package/src/qs.ts +31 -0
  128. package/src/redirect.ts +181 -0
  129. package/src/request.ts +982 -0
  130. package/src/response.ts +1421 -0
  131. package/src/router/brisk.ts +113 -0
  132. package/src/router/executor.ts +36 -0
  133. package/src/router/factories/use_return_value.ts +26 -0
  134. package/src/router/group.ts +243 -0
  135. package/src/router/lookup_store/main.ts +102 -0
  136. package/src/router/lookup_store/route_finder.ts +60 -0
  137. package/src/router/lookup_store/url_builder.ts +250 -0
  138. package/src/router/main.ts +431 -0
  139. package/src/router/matchers.ts +40 -0
  140. package/src/router/parser.ts +20 -0
  141. package/src/router/resource.ts +277 -0
  142. package/src/router/route.ts +363 -0
  143. package/src/router/store.ts +239 -0
  144. package/src/server/factories/final_handler.ts +38 -0
  145. package/src/server/factories/middleware_handler.ts +23 -0
  146. package/src/server/factories/write_response.ts +26 -0
  147. package/src/server/main.ts +356 -0
  148. package/src/types/base.ts +30 -0
  149. package/src/types/main.ts +16 -0
  150. package/src/types/middleware.ts +59 -0
  151. package/src/types/qs.ts +85 -0
  152. package/src/types/request.ts +52 -0
  153. package/src/types/response.ts +57 -0
  154. package/src/types/route.ts +217 -0
  155. package/src/types/server.ts +92 -0
@@ -0,0 +1,290 @@
1
+ /*
2
+ * @adonisjs/http-server
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+
10
+ import is from '@sindresorhus/is'
11
+ import type { Level } from '@adonisjs/logger/types'
12
+
13
+ import { parseRange } from './helpers.js'
14
+ import * as errors from './exceptions.js'
15
+ import type { HttpContext } from './http_context/main.js'
16
+ import type { HttpError, StatusPageRange, StatusPageRenderer } from './types/server.js'
17
+
18
+ /**
19
+ * The base HTTP exception handler one can inherit from to handle
20
+ * HTTP exceptions.
21
+ *
22
+ * The HTTP exception handler has support for
23
+ *
24
+ * - Ability to render exceptions by calling the render method on the exception.
25
+ * - Rendering status pages
26
+ * - Pretty printing errors during development
27
+ * - Transforming errors to JSON or HTML using content negotiation
28
+ * - Reporting errors
29
+ */
30
+ export class ExceptionHandler {
31
+ /**
32
+ * Whether or not to render debug info. When set to true, the errors
33
+ * will have the complete error stack.
34
+ */
35
+ protected debug: boolean = process.env.NODE_ENV !== 'production'
36
+
37
+ /**
38
+ * Whether or not to render status pages. When set to true, the unhandled
39
+ * errors with matching status codes will be rendered using a status
40
+ * page.
41
+ */
42
+ protected renderStatusPages: boolean = process.env.NODE_ENV === 'production'
43
+
44
+ /**
45
+ * A collection of error status code range and the view to render.
46
+ */
47
+ protected statusPages: Record<StatusPageRange, StatusPageRenderer> = {}
48
+
49
+ /**
50
+ * Computed from the status pages property
51
+ */
52
+ #expandedStatusPages?: Record<number, StatusPageRenderer>
53
+
54
+ /**
55
+ * Renderers for rendering an error.
56
+ */
57
+ protected renderers: {
58
+ html: (error: HttpError, ctx: HttpContext) => Promise<void>
59
+ json: (error: HttpError, ctx: HttpContext) => Promise<void>
60
+ json_api: (error: HttpError, ctx: HttpContext) => Promise<void>
61
+ } = {
62
+ html: async (error: HttpError, ctx: HttpContext) => {
63
+ if (this.isDebuggingEnabled(ctx)) {
64
+ const { default: Youch } = await import('youch')
65
+ const html = await new Youch(error, ctx.request.request).toHTML()
66
+ ctx.response.status(error.status).send(html)
67
+
68
+ return
69
+ }
70
+
71
+ ctx.response.status(error.status).send(`<p> ${error.message} </p>`)
72
+ },
73
+
74
+ json: async (error: HttpError, ctx: HttpContext) => {
75
+ if (this.isDebuggingEnabled(ctx)) {
76
+ const { default: Youch } = await import('youch')
77
+ const json = await new Youch(error, ctx.request.request).toJSON()
78
+ ctx.response.status(error.status).send(json.error)
79
+
80
+ return
81
+ }
82
+
83
+ ctx.response.status(error.status).send({ message: error.message })
84
+ },
85
+
86
+ json_api: async (error: HttpError, ctx: HttpContext) => {
87
+ if (this.isDebuggingEnabled(ctx)) {
88
+ const { default: Youch } = await import('youch')
89
+ const json = await new Youch(error, ctx.request.request).toJSON()
90
+ ctx.response.status(error.status).send(json.error)
91
+
92
+ return
93
+ }
94
+
95
+ ctx.response.status(error.status).send({
96
+ errors: [
97
+ {
98
+ title: error.message,
99
+ code: error.code,
100
+ status: error.status,
101
+ },
102
+ ],
103
+ })
104
+ },
105
+ }
106
+
107
+ /**
108
+ * Enable/disable errors reporting
109
+ */
110
+ protected reportErrors: boolean = true
111
+
112
+ /**
113
+ * An array of exception classes to ignore when
114
+ * reporting an error
115
+ */
116
+ protected ignoreExceptions: any[] = [
117
+ errors.E_HTTP_EXCEPTION,
118
+ errors.E_ROUTE_NOT_FOUND,
119
+ errors.E_CANNOT_LOOKUP_ROUTE,
120
+ errors.E_HTTP_REQUEST_ABORTED,
121
+ ]
122
+
123
+ /**
124
+ * An array of HTTP status codes to ignore when reporting
125
+ * an error
126
+ */
127
+ protected ignoreStatuses: number[] = [400, 422, 401]
128
+
129
+ /**
130
+ * An array of error codes to ignore when reporting
131
+ * an error
132
+ */
133
+ protected ignoreCodes: string[] = []
134
+
135
+ /**
136
+ * Expands status pages
137
+ */
138
+ #expandStatusPages() {
139
+ if (!this.#expandedStatusPages) {
140
+ this.#expandedStatusPages = Object.keys(this.statusPages).reduce((result, range) => {
141
+ const renderer = this.statusPages[range as StatusPageRange]
142
+ result = Object.assign(result, parseRange(range, renderer))
143
+ return result
144
+ }, {} as Record<number, StatusPageRenderer>)
145
+ }
146
+
147
+ return this.#expandedStatusPages
148
+ }
149
+
150
+ /**
151
+ * Forcefully tweaking the type of the error object to
152
+ * have known properties.
153
+ */
154
+ #toHttpError(error: unknown): HttpError {
155
+ const httpError: any = is.object(error) ? error : new Error(String(error))
156
+ httpError.message = httpError.message || 'Internal server error'
157
+ httpError.status = httpError.status || 500
158
+ return httpError
159
+ }
160
+
161
+ /**
162
+ * Error reporting context
163
+ */
164
+ protected context(ctx: HttpContext): any {
165
+ const requestId = ctx.request.id()
166
+ return requestId
167
+ ? {
168
+ 'x-request-id': requestId,
169
+ }
170
+ : {}
171
+ }
172
+
173
+ /**
174
+ * The format in which the error should be rendered.
175
+ */
176
+ protected getResponseFormat(ctx: HttpContext): 'html' | 'json' | 'json_api' {
177
+ switch (ctx.request.accepts(['html', 'application/vnd.api+json', 'json'])) {
178
+ case 'application/vnd.api+json':
179
+ return 'json_api'
180
+ case 'json':
181
+ return 'json'
182
+ case 'html':
183
+ default:
184
+ return 'html'
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Returns the log level for an error based upon the error
190
+ * status code.
191
+ */
192
+ protected getErrorLogLevel(error: HttpError): Level {
193
+ if (error.status >= 500) {
194
+ return 'error'
195
+ }
196
+
197
+ if (error.status >= 400) {
198
+ return 'warn'
199
+ }
200
+
201
+ return 'info'
202
+ }
203
+
204
+ /**
205
+ * A boolean to control if errors should be rendered with
206
+ * all the available debugging info.
207
+ */
208
+ protected isDebuggingEnabled(_: HttpContext): boolean {
209
+ return this.debug
210
+ }
211
+
212
+ /**
213
+ * Returns a boolean by checking if an error should be reported.
214
+ */
215
+ protected shouldReport(error: HttpError): boolean {
216
+ if (this.reportErrors === false) {
217
+ return false
218
+ }
219
+
220
+ if (this.ignoreStatuses.includes(error.status)) {
221
+ return false
222
+ }
223
+
224
+ if (error.code && this.ignoreCodes.includes(error.code)) {
225
+ return false
226
+ }
227
+
228
+ if (this.ignoreExceptions.find((exception) => error instanceof exception)) {
229
+ return false
230
+ }
231
+
232
+ return true
233
+ }
234
+
235
+ /**
236
+ * Reports an error during an HTTP request
237
+ */
238
+ async report(error: unknown, ctx: HttpContext) {
239
+ const httpError = this.#toHttpError(error)
240
+ if (!this.shouldReport(httpError)) {
241
+ return
242
+ }
243
+
244
+ if (typeof httpError.report === 'function') {
245
+ httpError.report(httpError, ctx)
246
+ return
247
+ }
248
+
249
+ /**
250
+ * Log the error using the logger
251
+ */
252
+ const level = this.getErrorLogLevel(httpError)
253
+ ctx.logger.log(
254
+ level,
255
+ {
256
+ ...(level === 'error' || level === 'fatal' ? { err: httpError } : {}),
257
+ ...this.context(ctx),
258
+ },
259
+ httpError.message
260
+ )
261
+ }
262
+
263
+ /**
264
+ * Handles the error during the HTTP request.
265
+ */
266
+ async handle(error: unknown, ctx: HttpContext) {
267
+ const httpError = this.#toHttpError(error)
268
+
269
+ /**
270
+ * Self handle exception
271
+ */
272
+ if (typeof httpError.handle === 'function') {
273
+ return httpError.handle(httpError, ctx)
274
+ }
275
+
276
+ /**
277
+ * Render status page
278
+ */
279
+ const statusPages = this.#expandStatusPages()
280
+ if (this.renderStatusPages && statusPages[httpError.status]) {
281
+ return statusPages[httpError.status](httpError, ctx)
282
+ }
283
+
284
+ /**
285
+ * Use the format renderers.
286
+ */
287
+ const responseFormat = this.getResponseFormat(ctx)
288
+ return this.renderers[responseFormat](httpError, ctx)
289
+ }
290
+ }
@@ -0,0 +1,55 @@
1
+ /*
2
+ * @adonisjs/http-server
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+
10
+ import { createError, Exception } from '@poppinss/utils'
11
+ import type { HttpContext } from './http_context/main.js'
12
+
13
+ export const E_ROUTE_NOT_FOUND = createError<[method: string, url: string]>(
14
+ 'Cannot %s:%s',
15
+ 'E_ROUTE_NOT_FOUND',
16
+ 404
17
+ )
18
+
19
+ export const E_CANNOT_LOOKUP_ROUTE = createError<[routeIdentifier: string]>(
20
+ 'Cannot lookup route "%s"',
21
+ 'E_CANNOT_LOOKUP_ROUTE',
22
+ 500
23
+ )
24
+
25
+ export const E_HTTP_EXCEPTION = class HttpException extends Exception {
26
+ body: any
27
+ static code = 'E_HTTP_EXCEPTION'
28
+
29
+ /**
30
+ * This method returns an instance of the exception class
31
+ */
32
+ static invoke(body: any, status: number, code: string = 'E_HTTP_EXCEPTION'): HttpException {
33
+ if (body === null || body === undefined) {
34
+ const error = new this('HTTP Exception', { status, code })
35
+ error.body = 'Internal server error'
36
+ return error
37
+ }
38
+
39
+ if (typeof body === 'object') {
40
+ const error = new this(body.message || 'HTTP Exception', { status, code })
41
+ error.body = body
42
+ return error
43
+ }
44
+
45
+ const error = new this(body, { status, code })
46
+ error.body = body
47
+ return error
48
+ }
49
+ }
50
+
51
+ export const E_HTTP_REQUEST_ABORTED = class AbortException extends E_HTTP_EXCEPTION {
52
+ handle(error: AbortException, ctx: HttpContext) {
53
+ ctx.response.status(error.status).send(error.body)
54
+ }
55
+ }
package/src/helpers.ts ADDED
@@ -0,0 +1,108 @@
1
+ /*
2
+ * @adonisjs/http-server
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+
10
+ import Cache from 'tmp-cache'
11
+ import { InvalidArgumentsException } from '@poppinss/utils'
12
+
13
+ import { Route } from './router/route.js'
14
+ import { BriskRoute } from './router/brisk.js'
15
+ import { RouteGroup } from './router/group.js'
16
+ import type { RouteJSON } from './types/route.js'
17
+ import { RouteResource } from './router/resource.js'
18
+
19
+ const proxyCache = new Cache({ max: 200 })
20
+
21
+ /**
22
+ * Makes input string consistent by having only the starting
23
+ * slash
24
+ */
25
+ export function dropSlash(input: string): string {
26
+ if (input === '/') {
27
+ return '/'
28
+ }
29
+
30
+ return `/${input.replace(/^\//, '').replace(/\/$/, '')}`
31
+ }
32
+
33
+ /**
34
+ * Returns a flat list of routes from the route groups and resources
35
+ */
36
+ export function toRoutesJSON(
37
+ routes: (RouteGroup | Route | RouteResource | BriskRoute)[]
38
+ ): RouteJSON[] {
39
+ return routes.reduce((list: RouteJSON[], route) => {
40
+ if (route instanceof RouteGroup) {
41
+ list = list.concat(toRoutesJSON(route.routes))
42
+ return list
43
+ }
44
+
45
+ if (route instanceof RouteResource) {
46
+ list = list.concat(toRoutesJSON(route.routes))
47
+ return list
48
+ }
49
+
50
+ if (route instanceof BriskRoute) {
51
+ if (route.route && !route.route.isDeleted()) {
52
+ list.push(route.route.toJSON())
53
+ }
54
+ return list
55
+ }
56
+
57
+ if (!route.isDeleted()) {
58
+ list.push(route.toJSON())
59
+ }
60
+
61
+ return list
62
+ }, [])
63
+ }
64
+
65
+ /**
66
+ * Helper to know if the remote address should
67
+ * be trusted.
68
+ */
69
+ export function trustProxy(
70
+ remoteAddress: string,
71
+ proxyFn: (addr: string, distance: number) => boolean
72
+ ): boolean {
73
+ if (proxyCache.has(remoteAddress)) {
74
+ return proxyCache.get(remoteAddress) as boolean
75
+ }
76
+
77
+ const result = proxyFn(remoteAddress, 0)
78
+ proxyCache.set(remoteAddress, result)
79
+ return result
80
+ }
81
+
82
+ /**
83
+ * Parses a range expression to an object filled with the range
84
+ */
85
+ export function parseRange<T>(range: string, value: T): Record<number, T> {
86
+ const parts = range.split('..')
87
+ const min = Number(parts[0])
88
+ const max = Number(parts[1])
89
+
90
+ if (Number.isNaN(min) || Number.isNaN(max)) {
91
+ return {}
92
+ }
93
+
94
+ if (min === max) {
95
+ return {
96
+ [min]: value,
97
+ }
98
+ }
99
+
100
+ if (max < min) {
101
+ throw new InvalidArgumentsException(`Invalid range "${range}"`)
102
+ }
103
+
104
+ return [...Array(max - min + 1).keys()].reduce((result, step) => {
105
+ result[min + step] = value
106
+ return result
107
+ }, {} as Record<number, T>)
108
+ }
@@ -0,0 +1,50 @@
1
+ /*
2
+ * @adonisjs/http-server
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+
10
+ import { AsyncLocalStorage } from 'node:async_hooks'
11
+ import type { HttpContext } from './main.js'
12
+
13
+ /**
14
+ * Async local storage for HTTP context
15
+ */
16
+ export const asyncLocalStorage: {
17
+ isEnabled: boolean
18
+ storage: null | AsyncLocalStorage<HttpContext>
19
+ create(): AsyncLocalStorage<HttpContext>
20
+ destroy(): void
21
+ } = {
22
+ /**
23
+ * Check if the async local storage for the HTTP
24
+ * context is enabled or not
25
+ */
26
+ isEnabled: false,
27
+
28
+ /**
29
+ * HTTP context storage instance for the current scope
30
+ */
31
+ storage: null,
32
+
33
+ /**
34
+ * Create the storage instance. This method must be called only
35
+ * once.
36
+ */
37
+ create() {
38
+ this.isEnabled = true
39
+ this.storage = new AsyncLocalStorage<HttpContext>()
40
+ return this.storage
41
+ },
42
+
43
+ /**
44
+ * Destroy the create storage instance
45
+ */
46
+ destroy() {
47
+ this.isEnabled = false
48
+ this.storage = null
49
+ },
50
+ }
@@ -0,0 +1,126 @@
1
+ /*
2
+ * @adonisjs/http-server
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+
10
+ import { inspect } from 'node:util'
11
+ import Macroable from '@poppinss/macroable'
12
+ import type { Logger } from '@adonisjs/logger'
13
+ import { RuntimeException } from '@poppinss/utils'
14
+ import { ContainerResolver } from '@adonisjs/fold'
15
+
16
+ import type { Request } from '../request.js'
17
+ import type { Response } from '../response.js'
18
+ import { asyncLocalStorage } from './local_storage.js'
19
+ import type { StoreRouteNode } from '../types/route.js'
20
+
21
+ /**
22
+ * Http context encapsulates properties for a given HTTP request. The
23
+ * context class can be extended using macros and getters.
24
+ */
25
+ export class HttpContext extends Macroable {
26
+ /**
27
+ * Find if async localstorage is enabled for HTTP requests
28
+ * or not
29
+ */
30
+ static get usingAsyncLocalStorage() {
31
+ return asyncLocalStorage.isEnabled
32
+ }
33
+
34
+ /**
35
+ * Get access to the HTTP context. Available only when
36
+ * "usingAsyncLocalStorage" is true
37
+ */
38
+ static get(): HttpContext | null {
39
+ if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) {
40
+ return null
41
+ }
42
+
43
+ return asyncLocalStorage.storage.getStore() || null
44
+ }
45
+
46
+ /**
47
+ * Get the HttpContext instance or raise an exception if not
48
+ * available
49
+ */
50
+ static getOrFail(): HttpContext {
51
+ /**
52
+ * Localstorage is not enabled
53
+ */
54
+ if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) {
55
+ throw new RuntimeException(
56
+ 'HTTP context is not available. Enable "useAsyncLocalStorage" inside "config/app.ts" file'
57
+ )
58
+ }
59
+
60
+ const store = this.get()
61
+ if (!store) {
62
+ throw new RuntimeException('Http context is not available outside of an HTTP request')
63
+ }
64
+
65
+ return store
66
+ }
67
+
68
+ /**
69
+ * Run a method that doesn't have access to HTTP context from
70
+ * the async local storage.
71
+ */
72
+ static runOutsideContext<T>(callback: (...args: any[]) => T, ...args: any[]): T {
73
+ if (!asyncLocalStorage.storage) {
74
+ return callback(...args)
75
+ }
76
+
77
+ return asyncLocalStorage.storage.exit(callback, ...args)
78
+ }
79
+
80
+ /**
81
+ * Reference to the current route. Not available inside
82
+ * server middleware
83
+ */
84
+ route?: StoreRouteNode
85
+
86
+ /**
87
+ * A unique key for the current route
88
+ */
89
+ routeKey?: string
90
+
91
+ /**
92
+ * Route params
93
+ */
94
+ params: Record<string, any> = {}
95
+
96
+ /**
97
+ * Route subdomains
98
+ */
99
+ subdomains: Record<string, any> = {}
100
+
101
+ constructor(
102
+ public request: Request,
103
+ public response: Response,
104
+ public logger: Logger,
105
+ public containerResolver: ContainerResolver<any>
106
+ ) {
107
+ super()
108
+
109
+ /*
110
+ * Creating the circular reference. We do this, since request and response
111
+ * are meant to be extended and at times people would want to access
112
+ * other ctx properties like `logger`, `profiler` inside those
113
+ * extended methods.
114
+ */
115
+ this.request.ctx = this
116
+ this.response.ctx = this
117
+ }
118
+
119
+ /**
120
+ * A helper to see top level properties on the context object
121
+ */
122
+ /* c8 ignore next 3 */
123
+ inspect() {
124
+ return inspect(this, false, 1, true)
125
+ }
126
+ }
package/src/qs.ts ADDED
@@ -0,0 +1,31 @@
1
+ /*
2
+ * @adonisjs/http-server
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+
10
+ import { parse, stringify } from 'qs'
11
+ import { QSParserConfig } from './types/qs.js'
12
+
13
+ /**
14
+ * Query string parser used to parse and stringify query
15
+ * strings.
16
+ */
17
+ export class Qs {
18
+ #config: QSParserConfig
19
+
20
+ constructor(config: QSParserConfig) {
21
+ this.#config = config
22
+ }
23
+
24
+ parse(value: string) {
25
+ return parse(value, this.#config.parse)
26
+ }
27
+
28
+ stringify(value: any) {
29
+ return stringify(value, this.#config.stringify)
30
+ }
31
+ }