@adonisjs/http-server 7.0.0-0 → 7.0.0-1

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 (107) hide show
  1. package/build/factories/http_context.d.ts +25 -0
  2. package/build/factories/http_context.js +51 -0
  3. package/build/factories/http_server.d.ts +8 -0
  4. package/build/factories/http_server.js +26 -0
  5. package/build/factories/main.d.ts +6 -149
  6. package/build/factories/main.js +14 -331
  7. package/build/factories/qs_parser_factory.d.ts +20 -0
  8. package/build/factories/qs_parser_factory.js +44 -0
  9. package/build/factories/request.d.ts +29 -0
  10. package/build/factories/request.js +73 -0
  11. package/build/factories/response.d.ts +29 -0
  12. package/build/factories/response.js +77 -0
  13. package/build/factories/router.d.ts +23 -0
  14. package/build/factories/router.js +45 -0
  15. package/build/factories/server_factory.d.ts +29 -0
  16. package/build/factories/server_factory.js +65 -0
  17. package/build/index.d.ts +14 -272
  18. package/build/index.js +22 -308
  19. package/build/src/cookies/client.d.ts +37 -0
  20. package/build/src/cookies/client.js +84 -0
  21. package/build/src/cookies/drivers/encrypted.d.ts +16 -0
  22. package/build/src/cookies/drivers/encrypted.js +36 -0
  23. package/build/src/cookies/drivers/plain.d.ts +15 -0
  24. package/build/src/cookies/drivers/plain.js +33 -0
  25. package/build/src/cookies/drivers/signed.d.ts +16 -0
  26. package/build/src/cookies/drivers/signed.js +36 -0
  27. package/build/src/cookies/parser.d.ts +37 -0
  28. package/build/src/cookies/parser.js +167 -0
  29. package/build/src/cookies/serializer.d.ts +33 -0
  30. package/build/src/cookies/serializer.js +79 -0
  31. package/build/src/debug.d.ts +3 -0
  32. package/build/src/debug.js +10 -0
  33. package/build/src/define_config.d.ts +9 -0
  34. package/build/src/define_config.js +68 -0
  35. package/build/src/define_middleware.d.ts +11 -0
  36. package/build/src/define_middleware.js +35 -0
  37. package/build/src/exception_handler.d.ts +113 -0
  38. package/build/src/exception_handler.js +306 -0
  39. package/build/src/exceptions.d.ts +84 -0
  40. package/build/src/exceptions.js +38 -0
  41. package/build/src/helpers.d.ts +23 -0
  42. package/build/src/helpers.js +105 -0
  43. package/build/src/http_context/local_storage.d.ts +12 -0
  44. package/build/src/http_context/local_storage.js +39 -0
  45. package/build/src/http_context/main.d.ts +58 -0
  46. package/build/src/http_context/main.js +105 -0
  47. package/build/src/qs.d.ts +11 -0
  48. package/build/src/qs.js +25 -0
  49. package/build/src/redirect.d.ts +42 -0
  50. package/build/src/redirect.js +140 -0
  51. package/build/src/request.d.ts +565 -0
  52. package/build/src/request.js +865 -0
  53. package/build/src/response.d.ts +620 -0
  54. package/build/src/response.js +1208 -0
  55. package/build/src/router/brisk.d.ts +42 -0
  56. package/build/src/router/brisk.js +85 -0
  57. package/build/src/router/executor.d.ts +9 -0
  58. package/build/src/router/executor.js +30 -0
  59. package/build/src/router/factories/use_return_value.d.ts +6 -0
  60. package/build/src/router/factories/use_return_value.js +22 -0
  61. package/build/src/router/group.d.ts +65 -0
  62. package/build/src/router/group.js +207 -0
  63. package/build/src/router/lookup_store/main.d.ts +49 -0
  64. package/build/src/router/lookup_store/main.js +86 -0
  65. package/build/src/router/lookup_store/route_finder.d.ts +21 -0
  66. package/build/src/router/lookup_store/route_finder.js +49 -0
  67. package/build/src/router/lookup_store/url_builder.d.ts +52 -0
  68. package/build/src/router/lookup_store/url_builder.js +209 -0
  69. package/build/src/router/main.d.ts +128 -0
  70. package/build/src/router/main.js +316 -0
  71. package/build/src/router/matchers.d.ts +27 -0
  72. package/build/src/router/matchers.js +36 -0
  73. package/build/src/router/parser.d.ts +5 -0
  74. package/build/src/router/parser.js +17 -0
  75. package/build/src/router/resource.d.ts +54 -0
  76. package/build/src/router/resource.js +216 -0
  77. package/build/src/router/route.d.ts +92 -0
  78. package/build/src/router/route.js +293 -0
  79. package/build/src/router/store.d.ts +66 -0
  80. package/build/src/router/store.js +195 -0
  81. package/build/src/server/factories/final_handler.d.ts +10 -0
  82. package/build/src/server/factories/final_handler.js +30 -0
  83. package/build/src/server/factories/middleware_handler.d.ts +8 -0
  84. package/build/src/server/factories/middleware_handler.js +16 -0
  85. package/build/src/server/factories/write_response.d.ts +6 -0
  86. package/build/src/server/factories/write_response.js +24 -0
  87. package/build/{main-29eaaee4.d.ts → src/server/main.d.ts} +18 -13
  88. package/build/src/server/main.js +292 -0
  89. package/build/src/types/base.d.ts +19 -0
  90. package/build/src/types/base.js +9 -0
  91. package/build/src/types/main.d.ts +7 -14
  92. package/build/src/types/main.js +15 -0
  93. package/build/src/types/middleware.d.ts +35 -0
  94. package/build/src/types/middleware.js +9 -0
  95. package/build/src/types/qs.d.ts +68 -0
  96. package/build/src/types/qs.js +9 -0
  97. package/build/src/types/request.d.ts +39 -0
  98. package/build/src/types/request.js +9 -0
  99. package/build/src/types/response.d.ts +45 -0
  100. package/build/src/types/response.js +9 -0
  101. package/build/src/types/route.d.ts +166 -0
  102. package/build/src/types/route.js +9 -0
  103. package/build/src/types/server.d.ts +72 -0
  104. package/build/src/types/server.js +9 -0
  105. package/package.json +6 -3
  106. package/build/chunk-XX72ATFY.js +0 -4388
  107. package/build/main-e5b46c83.d.ts +0 -2210
@@ -1,4388 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/router/route.ts
8
- import is from "@sindresorhus/is";
9
- import Macroable4 from "@poppinss/macroable";
10
- import Middleware from "@poppinss/middleware";
11
- import { RuntimeException as RuntimeException2 } from "@poppinss/utils";
12
- import { moduleCaller, moduleExpression, moduleImporter } from "@adonisjs/fold";
13
-
14
- // src/router/factories/use_return_value.ts
15
- function useReturnValue(ctx) {
16
- return function(value) {
17
- if (value !== void 0 && // Return value is explicitly defined
18
- !ctx.response.hasLazyBody && // Lazy body is not set
19
- value !== ctx.response) {
20
- ctx.response.send(value);
21
- }
22
- };
23
- }
24
-
25
- // src/router/executor.ts
26
- function execute(route, resolver, ctx, errorResponder) {
27
- return route.middleware.runner().errorHandler((error) => errorResponder(error, ctx)).finalHandler(async () => {
28
- if (typeof route.handler === "function") {
29
- return Promise.resolve(route.handler(ctx)).then(useReturnValue(ctx));
30
- }
31
- return route.handler.handle(resolver, ctx).then(useReturnValue(ctx));
32
- }).run(async (middleware, next) => {
33
- if (typeof middleware === "function") {
34
- return middleware(ctx, next);
35
- }
36
- return middleware.handle(resolver, ctx, next, middleware.args);
37
- });
38
- }
39
-
40
- // src/helpers.ts
41
- import Cache from "tmp-cache";
42
- import { InvalidArgumentsException } from "@poppinss/utils";
43
-
44
- // src/router/brisk.ts
45
- import Macroable from "@poppinss/macroable";
46
- var BriskRoute = class extends Macroable {
47
- /**
48
- * Route pattern
49
- */
50
- #pattern;
51
- /**
52
- * Matchers inherited from the router
53
- */
54
- #globalMatchers;
55
- /**
56
- * Reference to the AdonisJS application
57
- */
58
- #app;
59
- /**
60
- * Middleware registered on the router
61
- */
62
- #routerMiddleware;
63
- /**
64
- * Reference to route instance. Set after `setHandler` is called
65
- */
66
- route = null;
67
- constructor(app, routerMiddleware, options) {
68
- super();
69
- this.#app = app;
70
- this.#routerMiddleware = routerMiddleware;
71
- this.#pattern = options.pattern;
72
- this.#globalMatchers = options.globalMatchers;
73
- }
74
- /**
75
- * Set handler for the brisk route
76
- */
77
- setHandler(handler) {
78
- this.route = new Route(this.#app, this.#routerMiddleware, {
79
- pattern: this.#pattern,
80
- globalMatchers: this.#globalMatchers,
81
- methods: ["GET", "HEAD"],
82
- handler
83
- });
84
- return this.route;
85
- }
86
- /**
87
- * Redirects to a given route. Params from the original request will
88
- * be used when no custom params are defined.
89
- */
90
- redirect(identifier, params, options) {
91
- return this.setHandler(async function redirectsToRoute(ctx) {
92
- const redirector = ctx.response.redirect();
93
- if (options?.status) {
94
- redirector.status(options.status);
95
- }
96
- return redirector.toRoute(identifier, params || ctx.params, options);
97
- });
98
- }
99
- /**
100
- * Redirect request to a fixed URL
101
- */
102
- redirectToPath(url, options) {
103
- return this.setHandler(async function redirectsToPath(ctx) {
104
- const redirector = ctx.response.redirect();
105
- if (options?.status) {
106
- redirector.status(options.status);
107
- }
108
- return redirector.toPath(url);
109
- });
110
- }
111
- };
112
-
113
- // src/router/group.ts
114
- import Macroable3 from "@poppinss/macroable";
115
-
116
- // src/router/resource.ts
117
- import string from "@poppinss/utils/string";
118
- import Macroable2 from "@poppinss/macroable";
119
- import { RuntimeException } from "@poppinss/utils";
120
- var RouteResource = class extends Macroable2 {
121
- /**
122
- * Resource identifier. Nested resources are separated
123
- * with a dot notation
124
- */
125
- #resource;
126
- /**
127
- * The controller to handle resource routing requests
128
- */
129
- #controller;
130
- /**
131
- * Is it a shallow resource? Shallow resources URLs do not have parent
132
- * resource name and id once they can be identified with the id.
133
- */
134
- #shallow = false;
135
- /**
136
- * Matchers inherited from the router
137
- */
138
- #globalMatchers;
139
- /**
140
- * Reference to the AdonisJS application
141
- */
142
- #app;
143
- /**
144
- * Middleware registered on the router
145
- */
146
- #routerMiddleware;
147
- /**
148
- * Parameter names for the resources. Defaults to `id` for
149
- * a singular resource and `resource_id` for nested
150
- * resources.
151
- */
152
- #params = {};
153
- /**
154
- * Base name for the routes. We suffix action names
155
- * on top of the base name
156
- */
157
- #routesBaseName;
158
- /**
159
- * A collection of routes instances that belongs to this resource
160
- */
161
- routes = [];
162
- constructor(app, routerMiddleware, options) {
163
- super();
164
- this.#validateResourceName(options.resource);
165
- this.#app = app;
166
- this.#shallow = options.shallow;
167
- this.#routerMiddleware = routerMiddleware;
168
- this.#controller = options.controller;
169
- this.#globalMatchers = options.globalMatchers;
170
- this.#resource = this.#normalizeResourceName(options.resource);
171
- this.#routesBaseName = this.#getRoutesBaseName();
172
- this.#buildRoutes();
173
- }
174
- /**
175
- * Normalizes the resource name to dropping leading and trailing
176
- * slashes.
177
- */
178
- #normalizeResourceName(resource) {
179
- return resource.replace(/^\//, "").replace(/\/$/, "");
180
- }
181
- /**
182
- * Ensure resource name is not an empty string
183
- */
184
- #validateResourceName(resource) {
185
- if (!resource || resource === "/") {
186
- throw new RuntimeException(`Invalid resource name "${resource}"`);
187
- }
188
- }
189
- /**
190
- * Converting segments of a resource to snake case to
191
- * make the route name.
192
- */
193
- #getRoutesBaseName() {
194
- return this.#resource.split(".").map((token) => string.snakeCase(token)).join(".");
195
- }
196
- /**
197
- * Create a new route for the given pattern, methods and controller action
198
- */
199
- #createRoute(pattern, methods, action) {
200
- const route = new Route(this.#app, this.#routerMiddleware, {
201
- pattern,
202
- methods,
203
- handler: typeof this.#controller === "string" ? `${this.#controller}.${action}` : [this.#controller, action],
204
- globalMatchers: this.#globalMatchers
205
- });
206
- route.as(`${this.#routesBaseName}.${action}`);
207
- this.routes.push(route);
208
- }
209
- /**
210
- * Returns the `resource_id` name for a given resource. The
211
- * resource name is converted to singular form and
212
- * transformed to snake case.
213
- *
214
- * photos becomes photo_id
215
- * users becomes user_id
216
- */
217
- #getResourceId(resource) {
218
- return `${string.snakeCase(string.singular(resource))}_id`;
219
- }
220
- /**
221
- * Build routes for the given resource
222
- */
223
- #buildRoutes() {
224
- const resources = this.#resource.split(".");
225
- const mainResource = resources.pop();
226
- this.#params[mainResource] = ":id";
227
- const baseURI = `${resources.map((resource) => {
228
- const paramName = `:${this.#getResourceId(resource)}`;
229
- this.#params[resource] = paramName;
230
- return `${resource}/${paramName}`;
231
- }).join("/")}/${mainResource}`;
232
- this.#createRoute(baseURI, ["GET", "HEAD"], "index");
233
- this.#createRoute(`${baseURI}/create`, ["GET", "HEAD"], "create");
234
- this.#createRoute(baseURI, ["POST"], "store");
235
- this.#createRoute(`${this.#shallow ? mainResource : baseURI}/:id`, ["GET", "HEAD"], "show");
236
- this.#createRoute(`${this.#shallow ? mainResource : baseURI}/:id/edit`, ["GET", "HEAD"], "edit");
237
- this.#createRoute(`${this.#shallow ? mainResource : baseURI}/:id`, ["PUT", "PATCH"], "update");
238
- this.#createRoute(`${this.#shallow ? mainResource : baseURI}/:id`, ["DELETE"], "destroy");
239
- }
240
- /**
241
- * Filter the routes based on their partial names
242
- */
243
- #filter(names, inverse) {
244
- const actions = Array.isArray(names) ? names : [names];
245
- return this.routes.filter((route) => {
246
- const match = actions.find((name) => route.getName().endsWith(name));
247
- return inverse ? !match : match;
248
- });
249
- }
250
- /**
251
- * Register only given routes and remove others
252
- */
253
- only(names) {
254
- this.#filter(names, true).forEach((route) => route.markAsDeleted());
255
- return this;
256
- }
257
- /**
258
- * Register all routes, except the one's defined
259
- */
260
- except(names) {
261
- this.#filter(names, false).forEach((route) => route.markAsDeleted());
262
- return this;
263
- }
264
- /**
265
- * Register api only routes. The `create` and `edit` routes, which
266
- * are meant to show forms will not be registered
267
- */
268
- apiOnly() {
269
- return this.except(["create", "edit"]);
270
- }
271
- /**
272
- * Define matcher for params inside the resource
273
- */
274
- where(key, matcher) {
275
- this.routes.forEach((route) => {
276
- route.where(key, matcher);
277
- });
278
- return this;
279
- }
280
- tap(actions, callback) {
281
- if (typeof actions === "function") {
282
- this.routes.forEach((route) => actions(route));
283
- return this;
284
- }
285
- this.#filter(actions, false).forEach((route) => callback(route));
286
- return this;
287
- }
288
- /**
289
- * Set the param name for a given resource
290
- */
291
- params(resources) {
292
- Object.keys(resources).forEach((resource) => {
293
- const param = resources[resource];
294
- const existingParam = this.#params[resource];
295
- this.#params[resource] = `:${param}`;
296
- this.routes.forEach((route) => {
297
- route.setPattern(
298
- route.getPattern().replace(`${resource}/${existingParam}`, `${resource}/:${param}`)
299
- );
300
- });
301
- });
302
- return this;
303
- }
304
- /**
305
- * Prepend name to all the routes
306
- */
307
- as(name, normalizeName = true) {
308
- name = normalizeName ? string.snakeCase(name) : name;
309
- this.routes.forEach((route) => {
310
- route.as(route.getName().replace(this.#routesBaseName, name), false);
311
- });
312
- this.#routesBaseName = name;
313
- return this;
314
- }
315
- };
316
-
317
- // src/router/group.ts
318
- var RouteGroup = class _RouteGroup extends Macroable3 {
319
- constructor(routes) {
320
- super();
321
- this.routes = routes;
322
- }
323
- /**
324
- * Array of middleware registered on the group.
325
- */
326
- #middleware = [];
327
- /**
328
- * Shares midldeware stack with the routes. The method is invoked recursively
329
- * to only register middleware with the route class and not with the
330
- * resource or the child group
331
- */
332
- #shareMiddlewareStackWithRoutes(route) {
333
- if (route instanceof _RouteGroup) {
334
- route.routes.forEach((child) => this.#shareMiddlewareStackWithRoutes(child));
335
- return;
336
- }
337
- if (route instanceof RouteResource) {
338
- route.routes.forEach((child) => child.getMiddleware().unshift(this.#middleware));
339
- return;
340
- }
341
- if (route instanceof BriskRoute) {
342
- route.route.getMiddleware().unshift(this.#middleware);
343
- return;
344
- }
345
- route.getMiddleware().unshift(this.#middleware);
346
- }
347
- /**
348
- * Updates the route name. The method is invoked recursively to only update
349
- * the name with the route class and not with the resource or the child
350
- * group.
351
- */
352
- #updateRouteName(route, name) {
353
- if (route instanceof _RouteGroup) {
354
- route.routes.forEach((child) => this.#updateRouteName(child, name));
355
- return;
356
- }
357
- if (route instanceof RouteResource) {
358
- route.routes.forEach((child) => child.as(name, true));
359
- return;
360
- }
361
- if (route instanceof BriskRoute) {
362
- route.route.as(name, true);
363
- return;
364
- }
365
- route.as(name, true);
366
- }
367
- /**
368
- * Sets prefix on the route. The method is invoked recursively to only set
369
- * the prefix with the route class and not with the resource or the
370
- * child group.
371
- */
372
- #setRoutePrefix(route, prefix) {
373
- if (route instanceof _RouteGroup) {
374
- route.routes.forEach((child) => this.#setRoutePrefix(child, prefix));
375
- return;
376
- }
377
- if (route instanceof RouteResource) {
378
- route.routes.forEach((child) => child.prefix(prefix));
379
- return;
380
- }
381
- if (route instanceof BriskRoute) {
382
- route.route.prefix(prefix);
383
- return;
384
- }
385
- route.prefix(prefix);
386
- }
387
- /**
388
- * Updates domain on the route. The method is invoked recursively to only update
389
- * the domain with the route class and not with the resource or the child
390
- * group.
391
- */
392
- #updateRouteDomain(route, domain) {
393
- if (route instanceof _RouteGroup) {
394
- route.routes.forEach((child) => this.#updateRouteDomain(child, domain));
395
- return;
396
- }
397
- if (route instanceof RouteResource) {
398
- route.routes.forEach((child) => child.domain(domain));
399
- return;
400
- }
401
- if (route instanceof BriskRoute) {
402
- route.route.domain(domain, false);
403
- return;
404
- }
405
- route.domain(domain, false);
406
- }
407
- /**
408
- * Updates matchers on the route. The method is invoked recursively to only update
409
- * the matchers with the route class and not with the resource or the child
410
- * group.
411
- */
412
- #updateRouteMatchers(route, param, matcher) {
413
- if (route instanceof _RouteGroup) {
414
- route.routes.forEach((child) => this.#updateRouteMatchers(child, param, matcher));
415
- return;
416
- }
417
- if (route instanceof RouteResource) {
418
- route.routes.forEach((child) => child.where(param, matcher));
419
- return;
420
- }
421
- if (route instanceof BriskRoute) {
422
- route.route.where(param, matcher);
423
- return;
424
- }
425
- route.where(param, matcher);
426
- }
427
- /**
428
- * Define route param matcher
429
- *
430
- * ```ts
431
- * Route.group(() => {
432
- * }).where('id', /^[0-9]+/)
433
- * ```
434
- */
435
- where(param, matcher) {
436
- this.routes.forEach((route) => this.#updateRouteMatchers(route, param, matcher));
437
- return this;
438
- }
439
- /**
440
- * Define prefix all the routes in the group.
441
- *
442
- * ```ts
443
- * Route.group(() => {
444
- * }).prefix('v1')
445
- * ```
446
- */
447
- prefix(prefix) {
448
- this.routes.forEach((route) => this.#setRoutePrefix(route, prefix));
449
- return this;
450
- }
451
- /**
452
- * Define domain for all the routes.
453
- *
454
- * ```ts
455
- * Route.group(() => {
456
- * }).domain(':name.adonisjs.com')
457
- * ```
458
- */
459
- domain(domain) {
460
- this.routes.forEach((route) => this.#updateRouteDomain(route, domain));
461
- return this;
462
- }
463
- /**
464
- * Prepend name to the routes name.
465
- *
466
- * ```ts
467
- * Route.group(() => {
468
- * }).as('version1')
469
- * ```
470
- */
471
- as(name) {
472
- this.routes.forEach((route) => this.#updateRouteName(route, name));
473
- return this;
474
- }
475
- /**
476
- * Prepend an array of middleware to all routes middleware.
477
- *
478
- * ```ts
479
- * Route.group(() => {
480
- * }).use(middleware.auth())
481
- * ```
482
- */
483
- use(middleware) {
484
- if (!this.#middleware.length) {
485
- this.routes.forEach((route) => this.#shareMiddlewareStackWithRoutes(route));
486
- }
487
- if (Array.isArray(middleware)) {
488
- for (let one of middleware) {
489
- this.#middleware.push(one);
490
- }
491
- } else {
492
- this.#middleware.push(middleware);
493
- }
494
- return this;
495
- }
496
- /**
497
- * @alias use
498
- */
499
- middleware(middleware) {
500
- return this.use(middleware);
501
- }
502
- };
503
-
504
- // src/helpers.ts
505
- var proxyCache = new Cache({ max: 200 });
506
- function dropSlash(input) {
507
- if (input === "/") {
508
- return "/";
509
- }
510
- return `/${input.replace(/^\//, "").replace(/\/$/, "")}`;
511
- }
512
- function toRoutesJSON(routes) {
513
- return routes.reduce((list, route) => {
514
- if (route instanceof RouteGroup) {
515
- list = list.concat(toRoutesJSON(route.routes));
516
- return list;
517
- }
518
- if (route instanceof RouteResource) {
519
- list = list.concat(toRoutesJSON(route.routes));
520
- return list;
521
- }
522
- if (route instanceof BriskRoute) {
523
- if (route.route && !route.route.isDeleted()) {
524
- list.push(route.route.toJSON());
525
- }
526
- return list;
527
- }
528
- if (!route.isDeleted()) {
529
- list.push(route.toJSON());
530
- }
531
- return list;
532
- }, []);
533
- }
534
- function trustProxy(remoteAddress, proxyFn) {
535
- if (proxyCache.has(remoteAddress)) {
536
- return proxyCache.get(remoteAddress);
537
- }
538
- const result = proxyFn(remoteAddress, 0);
539
- proxyCache.set(remoteAddress, result);
540
- return result;
541
- }
542
- function parseRange(range, value) {
543
- const parts = range.split("..");
544
- const min = Number(parts[0]);
545
- const max = Number(parts[1]);
546
- if (parts.length === 1 && !Number.isNaN(min)) {
547
- return {
548
- [min]: value
549
- };
550
- }
551
- if (Number.isNaN(min) || Number.isNaN(max)) {
552
- return {};
553
- }
554
- if (min === max) {
555
- return {
556
- [min]: value
557
- };
558
- }
559
- if (max < min) {
560
- throw new InvalidArgumentsException(`Invalid range "${range}"`);
561
- }
562
- return [...Array(max - min + 1).keys()].reduce(
563
- (result, step) => {
564
- result[min + step] = value;
565
- return result;
566
- },
567
- {}
568
- );
569
- }
570
-
571
- // src/debug.ts
572
- import { debuglog } from "node:util";
573
- var debug_default = debuglog("adonisjs:http");
574
-
575
- // src/router/route.ts
576
- var Route = class extends Macroable4 {
577
- /**
578
- * Route pattern
579
- */
580
- #pattern;
581
- /**
582
- * HTTP Methods for the route
583
- */
584
- #methods;
585
- /**
586
- * A unique name for the route
587
- */
588
- #name;
589
- /**
590
- * A boolean to prevent route from getting registered within
591
- * the store.
592
- *
593
- * This flag must be set before "Router.commit" method
594
- */
595
- #isDeleted = false;
596
- /**
597
- * Route handler
598
- */
599
- #handler;
600
- /**
601
- * Matchers inherited from the router
602
- */
603
- #globalMatchers;
604
- /**
605
- * Reference to the AdonisJS application
606
- */
607
- #app;
608
- /**
609
- * Middleware registered on the router
610
- */
611
- #routerMiddleware;
612
- /**
613
- * By default the route is part of the `root` domain. Root domain is used
614
- * when no domain is defined
615
- */
616
- #routeDomain = "root";
617
- /**
618
- * An object of matchers to be forwarded to the store. The matchers
619
- * list is populated by calling `where` method
620
- */
621
- #matchers = {};
622
- /**
623
- * Custom prefixes defined on the route or the route parent
624
- * groups
625
- */
626
- #prefixes = [];
627
- /**
628
- * Middleware defined directly on the route or the route parent
629
- * routes. We mantain an array for each layer of the stack
630
- */
631
- #middleware = [];
632
- constructor(app, routerMiddleware, options) {
633
- super();
634
- this.#app = app;
635
- this.#routerMiddleware = routerMiddleware;
636
- this.#pattern = options.pattern;
637
- this.#methods = options.methods;
638
- this.#handler = this.#resolveRouteHandle(options.handler);
639
- this.#globalMatchers = options.globalMatchers;
640
- }
641
- /**
642
- * Resolves the route handler string expression to a
643
- * handler method object
644
- */
645
- #resolveRouteHandle(handler) {
646
- if (typeof handler === "string") {
647
- return {
648
- reference: handler,
649
- ...moduleExpression(handler, this.#app.appRoot).toHandleMethod()
650
- };
651
- }
652
- if (Array.isArray(handler)) {
653
- if (is.class_(handler[0])) {
654
- return {
655
- reference: handler,
656
- ...moduleCaller(handler[0], handler[1] || "handle").toHandleMethod()
657
- };
658
- }
659
- return {
660
- reference: handler,
661
- ...moduleImporter(handler[0], handler[1] || "handle").toHandleMethod()
662
- };
663
- }
664
- return handler;
665
- }
666
- /**
667
- * Returns an object of param matchers by merging global and local
668
- * matchers. The local copy is given preference over the global
669
- * one's
670
- */
671
- #getMatchers() {
672
- return { ...this.#globalMatchers, ...this.#matchers };
673
- }
674
- /**
675
- * Returns a normalized pattern string by prefixing the `prefix` (if defined).
676
- */
677
- #computePattern() {
678
- const pattern = dropSlash(this.#pattern);
679
- const prefix = this.#prefixes.slice().reverse().map((one) => dropSlash(one)).join("");
680
- return prefix ? `${prefix}${pattern === "/" ? "" : pattern}` : pattern;
681
- }
682
- /**
683
- * Define matcher for a given param. If a matcher exists, then we do not
684
- * override that, since the routes inside a group will set matchers
685
- * before the group, so they should have priority over the group
686
- * matchers.
687
- *
688
- * ```ts
689
- * Route.group(() => {
690
- * Route.get('/:id', 'handler').where('id', /^[0-9]$/)
691
- * }).where('id', /[^a-z$]/)
692
- * ```
693
- *
694
- * The `/^[0-9]$/` will win over the matcher defined by the group
695
- */
696
- where(param, matcher) {
697
- if (this.#matchers[param]) {
698
- return this;
699
- }
700
- if (typeof matcher === "string") {
701
- this.#matchers[param] = { match: new RegExp(matcher) };
702
- } else if (is.regExp(matcher)) {
703
- this.#matchers[param] = { match: matcher };
704
- } else {
705
- this.#matchers[param] = matcher;
706
- }
707
- return this;
708
- }
709
- /**
710
- * Define prefix for the route. Calling this method multiple times
711
- * applies multiple prefixes in the reverse order.
712
- */
713
- prefix(prefix) {
714
- this.#prefixes.push(prefix);
715
- return this;
716
- }
717
- /**
718
- * Define a custom domain for the route. We do not overwrite the domain
719
- * unless `overwrite` flag is set to true.
720
- */
721
- domain(domain, overwrite = false) {
722
- if (this.#routeDomain === "root" || overwrite) {
723
- this.#routeDomain = domain;
724
- }
725
- return this;
726
- }
727
- /**
728
- * Define one or more middleware to be executed before the route
729
- * handler.
730
- *
731
- * Named middleware can be referenced using the name registered with
732
- * the router middleware store.
733
- */
734
- use(middleware) {
735
- this.#middleware.push(Array.isArray(middleware) ? middleware : [middleware]);
736
- return this;
737
- }
738
- /**
739
- * @alias use
740
- */
741
- middleware(middleware) {
742
- return this.use(middleware);
743
- }
744
- /**
745
- * Give a unique name to the route. Assinging a new unique removes the
746
- * existing name of the route.
747
- *
748
- * Setting prepends to true prefixes the name to the existing name.
749
- */
750
- as(name, prepend = false) {
751
- if (prepend) {
752
- if (!this.#name) {
753
- throw new RuntimeException2(
754
- `Routes inside a group must have names before calling "router.group.as"`
755
- );
756
- }
757
- this.#name = `${name}.${this.#name}`;
758
- return this;
759
- }
760
- this.#name = name;
761
- return this;
762
- }
763
- /**
764
- * Check if the route was marked to be deleted
765
- */
766
- isDeleted() {
767
- return this.#isDeleted;
768
- }
769
- /**
770
- * Mark route as deleted. Deleted routes are not registered
771
- * with the route store
772
- */
773
- markAsDeleted() {
774
- this.#isDeleted = true;
775
- }
776
- /**
777
- * Get the route name
778
- */
779
- getName() {
780
- return this.#name;
781
- }
782
- /**
783
- * Get the route pattern
784
- */
785
- getPattern() {
786
- return this.#pattern;
787
- }
788
- /**
789
- * Set the route pattern
790
- */
791
- setPattern(pattern) {
792
- this.#pattern = pattern;
793
- return this;
794
- }
795
- /**
796
- * Returns the stack of middleware registered on the route.
797
- * The value is shared by reference.
798
- */
799
- getMiddleware() {
800
- return this.#middleware;
801
- }
802
- /**
803
- * Returns the middleware instance for persistence inside the
804
- * store
805
- */
806
- #getMiddlewareForStore() {
807
- const middleware = new Middleware();
808
- this.#routerMiddleware.forEach((one) => {
809
- debug_default("adding global middleware to route %s, %O", this.#pattern, one);
810
- middleware.add(one);
811
- });
812
- this.#middleware.flat().forEach((one) => {
813
- debug_default("adding named middleware to route %s, %O", this.#pattern, one);
814
- middleware.add(one);
815
- });
816
- return middleware;
817
- }
818
- /**
819
- * Returns JSON representation of the route
820
- */
821
- toJSON() {
822
- return {
823
- domain: this.#routeDomain,
824
- pattern: this.#computePattern(),
825
- matchers: this.#getMatchers(),
826
- meta: {},
827
- name: this.#name,
828
- handler: this.#handler,
829
- methods: this.#methods,
830
- middleware: this.#getMiddlewareForStore(),
831
- execute
832
- };
833
- }
834
- };
835
-
836
- // src/cookies/drivers/plain.ts
837
- import { base64, MessageBuilder } from "@poppinss/utils";
838
- function pack(value) {
839
- if (value === void 0 || value === null) {
840
- return null;
841
- }
842
- return base64.urlEncode(new MessageBuilder().build(value));
843
- }
844
- function canUnpack(encodedValue) {
845
- return typeof encodedValue === "string";
846
- }
847
- function unpack(encodedValue) {
848
- return new MessageBuilder().verify(base64.urlDecode(encodedValue, "utf-8", false));
849
- }
850
-
851
- // src/cookies/drivers/signed.ts
852
- function pack2(key, value, encryption) {
853
- if (value === void 0 || value === null) {
854
- return null;
855
- }
856
- return `s:${encryption.verifier.sign(value, void 0, key)}`;
857
- }
858
- function canUnpack2(signedValue) {
859
- return typeof signedValue === "string" && signedValue.substring(0, 2) === "s:";
860
- }
861
- function unpack2(key, signedValue, encryption) {
862
- const value = signedValue.slice(2);
863
- if (!value) {
864
- return null;
865
- }
866
- return encryption.verifier.unsign(value, key);
867
- }
868
-
869
- // src/cookies/drivers/encrypted.ts
870
- function pack3(key, value, encryption) {
871
- if (value === void 0 || value === null) {
872
- return null;
873
- }
874
- return `e:${encryption.encrypt(value, void 0, key)}`;
875
- }
876
- function canUnpack3(encryptedValue) {
877
- return typeof encryptedValue === "string" && encryptedValue.substring(0, 2) === "e:";
878
- }
879
- function unpack3(key, encryptedValue, encryption) {
880
- const value = encryptedValue.slice(2);
881
- if (!value) {
882
- return null;
883
- }
884
- return encryption.decrypt(value, key);
885
- }
886
-
887
- // src/cookies/client.ts
888
- var CookieClient = class {
889
- #encryption;
890
- constructor(encryption) {
891
- this.#encryption = encryption;
892
- }
893
- /**
894
- * Encrypt a key value pair to be sent in the cookie header
895
- */
896
- encrypt(key, value) {
897
- return pack3(key, value, this.#encryption);
898
- }
899
- /**
900
- * Sign a key value pair to be sent in the cookie header
901
- */
902
- sign(key, value) {
903
- return pack2(key, value, this.#encryption);
904
- }
905
- /**
906
- * Encode a key value pair to be sent in the cookie header
907
- */
908
- encode(_, value) {
909
- return pack(value);
910
- }
911
- /**
912
- * Unsign a signed cookie value
913
- */
914
- unsign(key, value) {
915
- return canUnpack2(value) ? unpack2(key, value, this.#encryption) : null;
916
- }
917
- /**
918
- * Decrypt an encrypted cookie value
919
- */
920
- decrypt(key, value) {
921
- return canUnpack3(value) ? unpack3(key, value, this.#encryption) : null;
922
- }
923
- /**
924
- * Decode an encoded cookie value
925
- */
926
- decode(_, value) {
927
- return canUnpack(value) ? unpack(value) : null;
928
- }
929
- /**
930
- * Parse response cookie
931
- */
932
- parse(key, value) {
933
- if (canUnpack2(value)) {
934
- return unpack2(key, value, this.#encryption);
935
- }
936
- if (canUnpack3(value)) {
937
- return unpack3(key, value, this.#encryption);
938
- }
939
- if (canUnpack(value)) {
940
- return unpack(value);
941
- }
942
- }
943
- };
944
-
945
- // src/request.ts
946
- import fresh from "fresh";
947
- import typeIs from "type-is";
948
- import accepts from "accepts";
949
- import { isIP } from "node:net";
950
- import is2 from "@sindresorhus/is";
951
- import proxyaddr from "proxy-addr";
952
- import { safeEqual } from "@poppinss/utils";
953
- import Macroable5 from "@poppinss/macroable";
954
- import lodash from "@poppinss/utils/lodash";
955
- import { createId } from "@paralleldrive/cuid2";
956
- import { parse } from "node:url";
957
-
958
- // src/cookies/parser.ts
959
- import cookie from "cookie";
960
- var CookieParser = class {
961
- #client;
962
- /**
963
- * A copy of cached cookies, they are cached during a request after
964
- * initial decoding, unsigning or decrypting.
965
- */
966
- #cachedCookies = {
967
- signedCookies: {},
968
- plainCookies: {},
969
- encryptedCookies: {}
970
- };
971
- /**
972
- * An object of key-value pair collected by parsing
973
- * the request cookie header.
974
- */
975
- #cookies;
976
- constructor(cookieHeader, encryption) {
977
- this.#client = new CookieClient(encryption);
978
- this.#cookies = this.#parse(cookieHeader);
979
- }
980
- /**
981
- * Parses the request `cookie` header
982
- */
983
- #parse(cookieHeader) {
984
- if (!cookieHeader) {
985
- return {};
986
- }
987
- return cookie.parse(cookieHeader);
988
- }
989
- /**
990
- * Attempts to decode a cookie by the name. When calling this method,
991
- * you are assuming that the cookie was just encoded in the first
992
- * place and not signed or encrypted.
993
- */
994
- decode(key, encoded = true) {
995
- const value = this.#cookies[key];
996
- if (value === null || value === void 0) {
997
- return null;
998
- }
999
- const cache = this.#cachedCookies.plainCookies;
1000
- if (cache[key] !== void 0) {
1001
- return cache[key];
1002
- }
1003
- const parsed = encoded ? this.#client.decode(key, value) : value;
1004
- if (parsed !== null) {
1005
- cache[key] = parsed;
1006
- }
1007
- return parsed;
1008
- }
1009
- /**
1010
- * Attempts to unsign a cookie by the name. When calling this method,
1011
- * you are assuming that the cookie was signed in the first place.
1012
- */
1013
- unsign(key) {
1014
- const value = this.#cookies[key];
1015
- if (value === null || value === void 0) {
1016
- return null;
1017
- }
1018
- const cache = this.#cachedCookies.signedCookies;
1019
- if (cache[key] !== void 0) {
1020
- return cache[key];
1021
- }
1022
- const parsed = this.#client.unsign(key, value);
1023
- if (parsed !== null) {
1024
- cache[key] = parsed;
1025
- }
1026
- return parsed;
1027
- }
1028
- /**
1029
- * Attempts to decrypt a cookie by the name. When calling this method,
1030
- * you are assuming that the cookie was encrypted in the first place.
1031
- */
1032
- decrypt(key) {
1033
- const value = this.#cookies[key];
1034
- if (value === null || value === void 0) {
1035
- return null;
1036
- }
1037
- const cache = this.#cachedCookies.encryptedCookies;
1038
- if (cache[key] !== void 0) {
1039
- return cache[key];
1040
- }
1041
- const parsed = this.#client.decrypt(key, value);
1042
- if (parsed !== null) {
1043
- cache[key] = parsed;
1044
- }
1045
- return parsed;
1046
- }
1047
- /**
1048
- * Returns an object of cookies key-value pair. Do note, the
1049
- * cookies are not decoded, unsigned or decrypted inside this
1050
- * list.
1051
- */
1052
- list() {
1053
- return this.#cookies;
1054
- }
1055
- };
1056
-
1057
- // src/request.ts
1058
- var Request = class extends Macroable5 {
1059
- constructor(request, response, encryption, config, qsParser) {
1060
- super();
1061
- this.request = request;
1062
- this.response = response;
1063
- this.#qsParser = qsParser;
1064
- this.#config = config;
1065
- this.#encryption = encryption;
1066
- this.parsedUrl = parse(this.request.url, false);
1067
- this.#parseQueryString();
1068
- }
1069
- /**
1070
- * Query string parser
1071
- */
1072
- #qsParser;
1073
- /**
1074
- * Encryption module to verify signed URLs and unsign/decrypt
1075
- * cookies
1076
- */
1077
- #encryption;
1078
- /**
1079
- * Request config
1080
- */
1081
- #config;
1082
- /**
1083
- * Request body set using `setBody` method
1084
- */
1085
- #requestBody = {};
1086
- /**
1087
- * A merged copy of `request body` and `querystring`
1088
- */
1089
- #requestData = {};
1090
- /**
1091
- * Original merged copy of `request body` and `querystring`.
1092
- * Further mutation to this object are not allowed
1093
- */
1094
- #originalRequestData = {};
1095
- /**
1096
- * Parsed query string
1097
- */
1098
- #requestQs = {};
1099
- /**
1100
- * Raw request body as text
1101
- */
1102
- #rawRequestBody;
1103
- /**
1104
- * Cached copy of `accepts` fn to do content
1105
- * negotiation.
1106
- */
1107
- #lazyAccepts;
1108
- /**
1109
- * Copy of lazily parsed signed and plain cookies.
1110
- */
1111
- #cookieParser;
1112
- /**
1113
- * Parses copy of the URL with query string as a string and not
1114
- * object. This is done to build URL's with query string without
1115
- * stringifying the object
1116
- */
1117
- parsedUrl;
1118
- /**
1119
- * The ctx will be set by the context itself. It creates a circular
1120
- * reference
1121
- */
1122
- ctx;
1123
- /**
1124
- * Parses the query string
1125
- */
1126
- #parseQueryString() {
1127
- if (this.parsedUrl.query) {
1128
- this.updateQs(this.#qsParser.parse(this.parsedUrl.query));
1129
- this.#originalRequestData = { ...this.#requestData };
1130
- }
1131
- }
1132
- /**
1133
- * Initiates the cookie parser lazily
1134
- */
1135
- #initiateCookieParser() {
1136
- if (!this.#cookieParser) {
1137
- this.#cookieParser = new CookieParser(this.header("cookie"), this.#encryption);
1138
- }
1139
- }
1140
- /**
1141
- * Lazily initiates the `accepts` module to make sure to parse
1142
- * the request headers only when one of the content-negotiation
1143
- * methods are used.
1144
- */
1145
- #initiateAccepts() {
1146
- this.#lazyAccepts = this.#lazyAccepts || accepts(this.request);
1147
- }
1148
- /**
1149
- * Returns the request id from the `x-request-id` header. The
1150
- * header is untouched, if it already exists.
1151
- */
1152
- id() {
1153
- let requestId = this.header("x-request-id");
1154
- if (!requestId && this.#config.generateRequestId) {
1155
- requestId = createId();
1156
- this.request.headers["x-request-id"] = requestId;
1157
- }
1158
- return requestId;
1159
- }
1160
- /**
1161
- * Set initial request body. A copy of the input will be maintained as the original
1162
- * request body. Since the request body and query string is subject to mutations, we
1163
- * keep one original reference to flash old data (whenever required).
1164
- *
1165
- * This method is supposed to be invoked by the body parser and must be called only
1166
- * once. For further mutations make use of `updateBody` method.
1167
- */
1168
- setInitialBody(body) {
1169
- if (this.#originalRequestData && Object.isFrozen(this.#originalRequestData)) {
1170
- throw new Error('Cannot re-set initial body. Use "request.updateBody" instead');
1171
- }
1172
- this.updateBody(body);
1173
- this.#originalRequestData = Object.freeze(lodash.cloneDeep(this.#requestData));
1174
- }
1175
- /**
1176
- * Update the request body with new data object. The `all` property
1177
- * will be re-computed by merging the query string and request
1178
- * body.
1179
- */
1180
- updateBody(body) {
1181
- this.#requestBody = body;
1182
- this.#requestData = { ...this.#requestBody, ...this.#requestQs };
1183
- }
1184
- /**
1185
- * Update the request raw body. Bodyparser sets this when unable to parse
1186
- * the request body or when request is multipart/form-data.
1187
- */
1188
- updateRawBody(rawBody) {
1189
- this.#rawRequestBody = rawBody;
1190
- }
1191
- /**
1192
- * Update the query string with the new data object. The `all` property
1193
- * will be re-computed by merging the query and the request body.
1194
- */
1195
- updateQs(data) {
1196
- this.#requestQs = data;
1197
- this.#requestData = { ...this.#requestBody, ...this.#requestQs };
1198
- }
1199
- /**
1200
- * Returns route params
1201
- */
1202
- params() {
1203
- return this.ctx?.params || {};
1204
- }
1205
- /**
1206
- * Returns the query string object by reference
1207
- */
1208
- qs() {
1209
- return this.#requestQs;
1210
- }
1211
- /**
1212
- * Returns reference to the request body
1213
- */
1214
- body() {
1215
- return this.#requestBody;
1216
- }
1217
- /**
1218
- * Returns reference to the merged copy of request body
1219
- * and query string
1220
- */
1221
- all() {
1222
- return this.#requestData;
1223
- }
1224
- /**
1225
- * Returns reference to the merged copy of original request
1226
- * query string and body
1227
- */
1228
- original() {
1229
- return this.#originalRequestData;
1230
- }
1231
- /**
1232
- * Returns the request raw body (if exists), or returns `null`.
1233
- *
1234
- * Ideally you must be dealing with the parsed body accessed using [[input]], [[all]] or
1235
- * [[post]] methods. The `raw` body is always a string.
1236
- */
1237
- raw() {
1238
- return this.#rawRequestBody || null;
1239
- }
1240
- /**
1241
- * Returns value for a given key from the request body or query string.
1242
- * The `defaultValue` is used when original value is `undefined`.
1243
- *
1244
- * @example
1245
- * ```js
1246
- * request.input('username')
1247
- *
1248
- * // with default value
1249
- * request.input('username', 'virk')
1250
- * ```
1251
- */
1252
- input(key, defaultValue) {
1253
- return lodash.get(this.#requestData, key, defaultValue);
1254
- }
1255
- /**
1256
- * Returns value for a given key from route params
1257
- *
1258
- * @example
1259
- * ```js
1260
- * request.param('id')
1261
- *
1262
- * // with default value
1263
- * request.param('id', 1)
1264
- * ```
1265
- */
1266
- param(key, defaultValue) {
1267
- return lodash.get(this.params(), key, defaultValue);
1268
- }
1269
- /**
1270
- * Get everything from the request body except the given keys.
1271
- *
1272
- * @example
1273
- * ```js
1274
- * request.except(['_csrf'])
1275
- * ```
1276
- */
1277
- except(keys) {
1278
- return lodash.omit(this.#requestData, keys);
1279
- }
1280
- /**
1281
- * Get value for specified keys.
1282
- *
1283
- * @example
1284
- * ```js
1285
- * request.only(['username', 'age'])
1286
- * ```
1287
- */
1288
- only(keys) {
1289
- return lodash.pick(this.#requestData, keys);
1290
- }
1291
- /**
1292
- * Returns the HTTP request method. This is the original
1293
- * request method. For spoofed request method, make
1294
- * use of [[method]].
1295
- *
1296
- * @example
1297
- * ```js
1298
- * request.intended()
1299
- * ```
1300
- */
1301
- intended() {
1302
- return this.request.method;
1303
- }
1304
- /**
1305
- * Returns the request HTTP method by taking method spoofing into account.
1306
- *
1307
- * Method spoofing works when all of the following are true.
1308
- *
1309
- * 1. `app.http.allowMethodSpoofing` config value is true.
1310
- * 2. request query string has `_method`.
1311
- * 3. The [[intended]] request method is `POST`.
1312
- *
1313
- * @example
1314
- * ```js
1315
- * request.method()
1316
- * ```
1317
- */
1318
- method() {
1319
- if (this.#config.allowMethodSpoofing && this.intended() === "POST") {
1320
- return this.input("_method", this.intended()).toUpperCase();
1321
- }
1322
- return this.intended();
1323
- }
1324
- /**
1325
- * Returns a copy of headers as an object
1326
- */
1327
- headers() {
1328
- return this.request.headers;
1329
- }
1330
- /**
1331
- * Returns value for a given header key. The default value is
1332
- * used when original value is `undefined`.
1333
- */
1334
- header(key, defaultValue) {
1335
- key = key.toLowerCase();
1336
- const headers = this.headers();
1337
- switch (key) {
1338
- case "referer":
1339
- case "referrer":
1340
- return headers.referrer || headers.referer || defaultValue;
1341
- default:
1342
- return headers[key] || defaultValue;
1343
- }
1344
- }
1345
- /**
1346
- * Returns the ip address of the user. This method is optimize to fetch
1347
- * ip address even when running your AdonisJs app behind a proxy.
1348
- *
1349
- * You can also define your own custom function to compute the ip address by
1350
- * defining `app.http.getIp` as a function inside the config file.
1351
- *
1352
- * ```js
1353
- * {
1354
- * http: {
1355
- * getIp (request) {
1356
- * // I am using nginx as a proxy server and want to trust 'x-real-ip'
1357
- * return request.header('x-real-ip')
1358
- * }
1359
- * }
1360
- * }
1361
- * ```
1362
- *
1363
- * You can control the behavior of trusting the proxy values by defining it
1364
- * inside the `config/app.js` file.
1365
- *
1366
- * ```js
1367
- * {
1368
- * http: {
1369
- * trustProxy: '127.0.0.1'
1370
- * }
1371
- * }
1372
- * ```
1373
- *
1374
- * The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
1375
- */
1376
- ip() {
1377
- const ipFn = this.#config.getIp;
1378
- if (typeof ipFn === "function") {
1379
- return ipFn(this);
1380
- }
1381
- return proxyaddr(this.request, this.#config.trustProxy);
1382
- }
1383
- /**
1384
- * Returns an array of ip addresses from most to least trusted one.
1385
- * This method is optimize to fetch ip address even when running
1386
- * your AdonisJs app behind a proxy.
1387
- *
1388
- * You can control the behavior of trusting the proxy values by defining it
1389
- * inside the `config/app.js` file.
1390
- *
1391
- * ```js
1392
- * {
1393
- * http: {
1394
- * trustProxy: '127.0.0.1'
1395
- * }
1396
- * }
1397
- * ```
1398
- *
1399
- * The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
1400
- */
1401
- ips() {
1402
- return proxyaddr.all(this.request, this.#config.trustProxy);
1403
- }
1404
- /**
1405
- * Returns the request protocol by checking for the URL protocol or
1406
- * `X-Forwarded-Proto` header.
1407
- *
1408
- * If the `trust` is evaluated to `false`, then URL protocol is returned,
1409
- * otherwise `X-Forwarded-Proto` header is used (if exists).
1410
- *
1411
- * You can control the behavior of trusting the proxy values by defining it
1412
- * inside the `config/app.js` file.
1413
- *
1414
- * ```js
1415
- * {
1416
- * http: {
1417
- * trustProxy: '127.0.0.1'
1418
- * }
1419
- * }
1420
- * ```
1421
- *
1422
- * The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
1423
- */
1424
- protocol() {
1425
- if ("encrypted" in this.request.socket) {
1426
- return "https";
1427
- }
1428
- if (!trustProxy(this.request.socket.remoteAddress, this.#config.trustProxy)) {
1429
- return this.parsedUrl.protocol || "http";
1430
- }
1431
- const forwardedProtocol = this.header("X-Forwarded-Proto");
1432
- return forwardedProtocol ? forwardedProtocol.split(/\s*,\s*/)[0] : "http";
1433
- }
1434
- /**
1435
- * Returns a boolean telling if request is served over `https`
1436
- * or not. Check [[protocol]] method to know how protocol is
1437
- * fetched.
1438
- */
1439
- secure() {
1440
- return this.protocol() === "https";
1441
- }
1442
- /**
1443
- * Returns the request host. If proxy headers are trusted, then
1444
- * `X-Forwarded-Host` is given priority over the `Host` header.
1445
- *
1446
- * You can control the behavior of trusting the proxy values by defining it
1447
- * inside the `config/app.js` file.
1448
- *
1449
- * ```js
1450
- * {
1451
- * http: {
1452
- * trustProxy: '127.0.0.1'
1453
- * }
1454
- * }
1455
- * ```
1456
- *
1457
- * The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
1458
- */
1459
- host() {
1460
- let host = this.header("host");
1461
- if (trustProxy(this.request.socket.remoteAddress, this.#config.trustProxy)) {
1462
- host = this.header("X-Forwarded-Host") || host;
1463
- }
1464
- if (!host) {
1465
- return null;
1466
- }
1467
- return host;
1468
- }
1469
- /**
1470
- * Returns the request hostname. If proxy headers are trusted, then
1471
- * `X-Forwarded-Host` is given priority over the `Host` header.
1472
- *
1473
- * You can control the behavior of trusting the proxy values by defining it
1474
- * inside the `config/app.js` file.
1475
- *
1476
- * ```js
1477
- * {
1478
- * http: {
1479
- * trustProxy: '127.0.0.1'
1480
- * }
1481
- * }
1482
- * ```
1483
- *
1484
- * The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
1485
- */
1486
- hostname() {
1487
- const host = this.host();
1488
- if (!host) {
1489
- return null;
1490
- }
1491
- const offset = host[0] === "[" ? host.indexOf("]") + 1 : 0;
1492
- const index = host.indexOf(":", offset);
1493
- return index !== -1 ? host.substring(0, index) : host;
1494
- }
1495
- /**
1496
- * Returns an array of subdomains for the given host. An empty array is
1497
- * returned if [[hostname]] is `null` or is an IP address.
1498
- *
1499
- * Also `www` is not considered as a subdomain
1500
- */
1501
- subdomains() {
1502
- const hostname = this.hostname();
1503
- if (!hostname || isIP(hostname)) {
1504
- return [];
1505
- }
1506
- const offset = this.#config.subdomainOffset;
1507
- const subdomains = hostname.split(".").reverse().slice(offset);
1508
- if (subdomains[subdomains.length - 1] === "www") {
1509
- subdomains.splice(subdomains.length - 1, 1);
1510
- }
1511
- return subdomains;
1512
- }
1513
- /**
1514
- * Returns a boolean telling, if request `X-Requested-With === 'xmlhttprequest'`
1515
- * or not.
1516
- */
1517
- ajax() {
1518
- const xRequestedWith = this.header("X-Requested-With", "");
1519
- return xRequestedWith.toLowerCase() === "xmlhttprequest";
1520
- }
1521
- /**
1522
- * Returns a boolean telling, if request has `X-Pjax` header
1523
- * set or not
1524
- */
1525
- pjax() {
1526
- return !!this.header("X-Pjax");
1527
- }
1528
- /**
1529
- * Returns the request relative URL.
1530
- *
1531
- * @example
1532
- * ```js
1533
- * request.url()
1534
- *
1535
- * // include query string
1536
- * request.url(true)
1537
- * ```
1538
- */
1539
- url(includeQueryString) {
1540
- const pathname = this.parsedUrl.pathname;
1541
- return includeQueryString && this.parsedUrl.query ? `${pathname}?${this.parsedUrl.query}` : pathname;
1542
- }
1543
- /**
1544
- * Returns the complete HTTP url by combining
1545
- * [[protocol]]://[[hostname]]/[[url]]
1546
- *
1547
- * @example
1548
- * ```js
1549
- * request.completeUrl()
1550
- *
1551
- * // include query string
1552
- * request.completeUrl(true)
1553
- * ```
1554
- */
1555
- completeUrl(includeQueryString) {
1556
- const protocol = this.protocol();
1557
- const hostname = this.host();
1558
- return `${protocol}://${hostname}${this.url(includeQueryString)}`;
1559
- }
1560
- /**
1561
- * Find if the current HTTP request is for the given route or the routes
1562
- */
1563
- matchesRoute(routeIdentifier) {
1564
- if (!this.ctx || !this.ctx.route) {
1565
- return false;
1566
- }
1567
- const route = this.ctx.route;
1568
- return !!(Array.isArray(routeIdentifier) ? routeIdentifier : [routeIdentifier]).find(
1569
- (identifier) => {
1570
- if (route.pattern === identifier || route.name === identifier) {
1571
- return true;
1572
- }
1573
- if (typeof route.handler === "function") {
1574
- return false;
1575
- }
1576
- return route.handler.reference === identifier;
1577
- }
1578
- );
1579
- }
1580
- /**
1581
- * Returns the best matching content type of the request by
1582
- * matching against the given types.
1583
- *
1584
- * The content type is picked from the `content-type` header and request
1585
- * must have body.
1586
- *
1587
- * The method response highly depends upon the types array values. Described below:
1588
- *
1589
- * | Type(s) | Return value |
1590
- * |----------|---------------|
1591
- * | ['json'] | json |
1592
- * | ['application/*'] | application/json |
1593
- * | ['vnd+json'] | application/json |
1594
- *
1595
- * @example
1596
- * ```js
1597
- * const bodyType = request.is(['json', 'xml'])
1598
- *
1599
- * if (bodyType === 'json') {
1600
- * // process JSON
1601
- * }
1602
- *
1603
- * if (bodyType === 'xml') {
1604
- * // process XML
1605
- * }
1606
- * ```
1607
- */
1608
- is(types) {
1609
- return typeIs(this.request, types) || null;
1610
- }
1611
- /**
1612
- * Returns the best type using `Accept` header and
1613
- * by matching it against the given types.
1614
- *
1615
- * If nothing is matched, then `null` will be returned
1616
- *
1617
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1618
- * docs too.
1619
- *
1620
- * @example
1621
- * ```js
1622
- * switch (request.accepts(['json', 'html'])) {
1623
- * case 'json':
1624
- * return response.json(user)
1625
- * case 'html':
1626
- * return view.render('user', { user })
1627
- * default:
1628
- * // decide yourself
1629
- * }
1630
- * ```
1631
- */
1632
- accepts(types) {
1633
- this.#initiateAccepts();
1634
- return this.#lazyAccepts.type(types) || null;
1635
- }
1636
- /**
1637
- * Return the types that the request accepts, in the order of the
1638
- * client's preference (most preferred first).
1639
- *
1640
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1641
- * docs too.
1642
- */
1643
- types() {
1644
- this.#initiateAccepts();
1645
- return this.#lazyAccepts.types();
1646
- }
1647
- /**
1648
- * Returns the best language using `Accept-language` header
1649
- * and by matching it against the given languages.
1650
- *
1651
- * If nothing is matched, then `null` will be returned
1652
- *
1653
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1654
- * docs too.
1655
- *
1656
- * @example
1657
- * ```js
1658
- * switch (request.language(['fr', 'de'])) {
1659
- * case 'fr':
1660
- * return view.render('about', { lang: 'fr' })
1661
- * case 'de':
1662
- * return view.render('about', { lang: 'de' })
1663
- * default:
1664
- * return view.render('about', { lang: 'en' })
1665
- * }
1666
- * ```
1667
- */
1668
- language(languages) {
1669
- this.#initiateAccepts();
1670
- return this.#lazyAccepts.language(languages) || null;
1671
- }
1672
- /**
1673
- * Return the languages that the request accepts, in the order of the
1674
- * client's preference (most preferred first).
1675
- *
1676
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1677
- * docs too.
1678
- */
1679
- languages() {
1680
- this.#initiateAccepts();
1681
- return this.#lazyAccepts.languages();
1682
- }
1683
- /**
1684
- * Returns the best charset using `Accept-charset` header
1685
- * and by matching it against the given charsets.
1686
- *
1687
- * If nothing is matched, then `null` will be returned
1688
- *
1689
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1690
- * docs too.
1691
- *
1692
- * @example
1693
- * ```js
1694
- * switch (request.charset(['utf-8', 'ISO-8859-1'])) {
1695
- * case 'utf-8':
1696
- * // make utf-8 friendly response
1697
- * case 'ISO-8859-1':
1698
- * // make ISO-8859-1 friendly response
1699
- * }
1700
- * ```
1701
- */
1702
- charset(charsets) {
1703
- this.#initiateAccepts();
1704
- return this.#lazyAccepts.charset(charsets) || null;
1705
- }
1706
- /**
1707
- * Return the charsets that the request accepts, in the order of the
1708
- * client's preference (most preferred first).
1709
- *
1710
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1711
- * docs too.
1712
- */
1713
- charsets() {
1714
- this.#initiateAccepts();
1715
- return this.#lazyAccepts.charsets();
1716
- }
1717
- /**
1718
- * Returns the best encoding using `Accept-encoding` header
1719
- * and by matching it against the given encodings.
1720
- *
1721
- * If nothing is matched, then `null` will be returned
1722
- *
1723
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1724
- * docs too.
1725
- */
1726
- encoding(encodings) {
1727
- this.#initiateAccepts();
1728
- return this.#lazyAccepts.encoding(encodings) || null;
1729
- }
1730
- /**
1731
- * Return the charsets that the request accepts, in the order of the
1732
- * client's preference (most preferred first).
1733
- *
1734
- * Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
1735
- * docs too.
1736
- */
1737
- encodings() {
1738
- this.#initiateAccepts();
1739
- return this.#lazyAccepts.encodings();
1740
- }
1741
- /**
1742
- * Returns a boolean telling if request has body
1743
- */
1744
- hasBody() {
1745
- return typeIs.hasBody(this.request);
1746
- }
1747
- /**
1748
- * Returns a boolean telling if the new response etag evaluates same
1749
- * as the request header `if-none-match`. In case of `true`, the
1750
- * server must return `304` response, telling the browser to
1751
- * use the client cache.
1752
- *
1753
- * You won't have to deal with this method directly, since AdonisJs will
1754
- * handle this for you when `http.etag = true` inside `config/app.js` file.
1755
- *
1756
- * However, this is how you can use it manually.
1757
- *
1758
- * ```js
1759
- * const responseBody = view.render('some-view')
1760
- *
1761
- * // sets the HTTP etag header for response
1762
- * response.setEtag(responseBody)
1763
- *
1764
- * if (request.fresh()) {
1765
- * response.sendStatus(304)
1766
- * } else {
1767
- * response.send(responseBody)
1768
- * }
1769
- * ```
1770
- */
1771
- fresh() {
1772
- if (["GET", "HEAD"].indexOf(this.intended()) === -1) {
1773
- return false;
1774
- }
1775
- const status = this.response.statusCode;
1776
- if (status >= 200 && status < 300 || status === 304) {
1777
- return fresh(this.headers(), this.response.getHeaders());
1778
- }
1779
- return false;
1780
- }
1781
- /**
1782
- * Opposite of [[fresh]]
1783
- */
1784
- stale() {
1785
- return !this.fresh();
1786
- }
1787
- /**
1788
- * Returns all parsed and signed cookies. Signed cookies ensures
1789
- * that their value isn't tampered.
1790
- */
1791
- cookiesList() {
1792
- this.#initiateCookieParser();
1793
- return this.#cookieParser.list();
1794
- }
1795
- /**
1796
- * Returns value for a given key from signed cookies. Optional
1797
- * defaultValue is returned when actual value is undefined.
1798
- */
1799
- cookie(key, defaultValue) {
1800
- this.#initiateCookieParser();
1801
- return this.#cookieParser.unsign(key) || defaultValue;
1802
- }
1803
- /**
1804
- * Returns value for a given key from signed cookies. Optional
1805
- * defaultValue is returned when actual value is undefined.
1806
- */
1807
- encryptedCookie(key, defaultValue) {
1808
- this.#initiateCookieParser();
1809
- return this.#cookieParser.decrypt(key) || defaultValue;
1810
- }
1811
- plainCookie(key, defaultValueOrOptions, encoded) {
1812
- this.#initiateCookieParser();
1813
- if (is2.object(defaultValueOrOptions)) {
1814
- return this.#cookieParser.decode(key, defaultValueOrOptions?.encoded) || defaultValueOrOptions.defaultValue;
1815
- }
1816
- return this.#cookieParser.decode(key, encoded) || defaultValueOrOptions;
1817
- }
1818
- /**
1819
- * Returns a boolean telling if a signed url as a valid signature
1820
- * or not.
1821
- */
1822
- hasValidSignature(purpose) {
1823
- const { signature, ...rest } = this.qs();
1824
- if (!signature) {
1825
- return false;
1826
- }
1827
- const signedUrl = this.#encryption.verifier.unsign(signature, purpose);
1828
- if (!signedUrl) {
1829
- return false;
1830
- }
1831
- const queryString = this.#qsParser.stringify(rest);
1832
- return queryString ? safeEqual(signedUrl, `${this.url()}?${queryString}`) : safeEqual(signedUrl, this.url());
1833
- }
1834
- /**
1835
- * Serializes request to JSON format
1836
- */
1837
- serialize() {
1838
- return {
1839
- id: this.id(),
1840
- url: this.url(),
1841
- query: this.parsedUrl.query,
1842
- body: this.all(),
1843
- params: this.params(),
1844
- headers: this.headers(),
1845
- method: this.method(),
1846
- protocol: this.protocol(),
1847
- cookies: this.cookiesList(),
1848
- hostname: this.hostname(),
1849
- ip: this.ip(),
1850
- subdomains: this.ctx?.subdomains || {}
1851
- };
1852
- }
1853
- /**
1854
- * toJSON copy of the request
1855
- */
1856
- toJSON() {
1857
- return this.serialize();
1858
- }
1859
- };
1860
-
1861
- // src/redirect.ts
1862
- import { parse as parse2 } from "node:url";
1863
- import encodeUrl from "encodeurl";
1864
- var Redirect = class {
1865
- /**
1866
- * A boolean to forward the existing query string
1867
- */
1868
- #forwardQueryString = false;
1869
- /**
1870
- * The status code for the redirect
1871
- */
1872
- #statusCode = 302;
1873
- /**
1874
- * A custom query string to forward
1875
- */
1876
- #queryString = {};
1877
- #request;
1878
- #response;
1879
- #router;
1880
- #qs;
1881
- constructor(request, response, router, qs) {
1882
- this.#request = request;
1883
- this.#response = response;
1884
- this.#router = router;
1885
- this.#qs = qs;
1886
- }
1887
- /**
1888
- * Sends response by setting require headers
1889
- */
1890
- #sendResponse(url, query) {
1891
- const stringified = this.#qs.stringify(query);
1892
- url = stringified ? `${url}?${stringified}` : url;
1893
- debug_default('redirecting to url "%s"', url);
1894
- this.#response.location(encodeUrl(url));
1895
- this.#response.safeStatus(this.#statusCode);
1896
- this.#response.type("text/plain; charset=utf-8");
1897
- this.#response.send(`Redirecting to ${url}`);
1898
- }
1899
- /**
1900
- * Returns the referrer url
1901
- */
1902
- #getReferrerUrl() {
1903
- let url = this.#request.headers["referer"] || this.#request.headers["referrer"] || "/";
1904
- return Array.isArray(url) ? url[0] : url;
1905
- }
1906
- /**
1907
- * Set a custom status code.
1908
- */
1909
- status(statusCode) {
1910
- this.#statusCode = statusCode;
1911
- return this;
1912
- }
1913
- /**
1914
- * Clearing query string values added using the
1915
- * "withQs" method
1916
- */
1917
- clearQs() {
1918
- this.#forwardQueryString = false;
1919
- this.#queryString = {};
1920
- return this;
1921
- }
1922
- withQs(name, value) {
1923
- if (typeof name === "undefined") {
1924
- this.#forwardQueryString = true;
1925
- return this;
1926
- }
1927
- if (typeof name === "string") {
1928
- this.#queryString[name] = value;
1929
- return this;
1930
- }
1931
- Object.assign(this.#queryString, name);
1932
- return this;
1933
- }
1934
- /**
1935
- * Redirect to the previous path.
1936
- */
1937
- back() {
1938
- let query = {};
1939
- const referrerUrl = this.#getReferrerUrl();
1940
- const url = parse2(referrerUrl);
1941
- debug_default('referrer url "%s"', referrerUrl);
1942
- debug_default('referrer base url "%s"', url.pathname);
1943
- if (this.#forwardQueryString) {
1944
- query = this.#qs.parse(url.query || "");
1945
- }
1946
- Object.assign(query, this.#queryString);
1947
- this.#sendResponse(url.pathname || "", query);
1948
- }
1949
- /**
1950
- * Redirect the request using a route identifier.
1951
- */
1952
- toRoute(routeIdentifier, params, options) {
1953
- if (options && options.qs) {
1954
- this.withQs(options.qs);
1955
- options.qs = void 0;
1956
- }
1957
- const url = this.#router.makeUrl(routeIdentifier, params, options);
1958
- return this.toPath(url);
1959
- }
1960
- /**
1961
- * Redirect the request using a path.
1962
- */
1963
- toPath(url) {
1964
- let query = {};
1965
- if (this.#forwardQueryString) {
1966
- query = this.#qs.parse(parse2(this.#request.url).query || "");
1967
- }
1968
- Object.assign(query, this.#queryString);
1969
- this.#sendResponse(url, query);
1970
- }
1971
- };
1972
-
1973
- // src/exceptions.ts
1974
- var exceptions_exports = {};
1975
- __export(exceptions_exports, {
1976
- E_CANNOT_LOOKUP_ROUTE: () => E_CANNOT_LOOKUP_ROUTE,
1977
- E_HTTP_EXCEPTION: () => E_HTTP_EXCEPTION,
1978
- E_HTTP_REQUEST_ABORTED: () => E_HTTP_REQUEST_ABORTED,
1979
- E_ROUTE_NOT_FOUND: () => E_ROUTE_NOT_FOUND
1980
- });
1981
- import { createError, Exception } from "@poppinss/utils";
1982
- var E_ROUTE_NOT_FOUND = createError(
1983
- "Cannot %s:%s",
1984
- "E_ROUTE_NOT_FOUND",
1985
- 404
1986
- );
1987
- var E_CANNOT_LOOKUP_ROUTE = createError(
1988
- 'Cannot lookup route "%s"',
1989
- "E_CANNOT_LOOKUP_ROUTE",
1990
- 500
1991
- );
1992
- var E_HTTP_EXCEPTION = class HttpException extends Exception {
1993
- body;
1994
- static code = "E_HTTP_EXCEPTION";
1995
- /**
1996
- * This method returns an instance of the exception class
1997
- */
1998
- static invoke(body, status, code = "E_HTTP_EXCEPTION") {
1999
- if (body === null || body === void 0) {
2000
- const error2 = new this("HTTP Exception", { status, code });
2001
- error2.body = "Internal server error";
2002
- return error2;
2003
- }
2004
- if (typeof body === "object") {
2005
- const error2 = new this(body.message || "HTTP Exception", { status, code });
2006
- error2.body = body;
2007
- return error2;
2008
- }
2009
- const error = new this(body, { status, code });
2010
- error.body = body;
2011
- return error;
2012
- }
2013
- };
2014
- var E_HTTP_REQUEST_ABORTED = class AbortException extends E_HTTP_EXCEPTION {
2015
- handle(error, ctx) {
2016
- ctx.response.status(error.status).send(error.body);
2017
- }
2018
- };
2019
-
2020
- // src/response.ts
2021
- import etag from "etag";
2022
- import vary from "vary";
2023
- import fresh2 from "fresh";
2024
- import mime from "mime-types";
2025
- import destroy from "destroy";
2026
- import { extname } from "node:path";
2027
- import onFinished from "on-finished";
2028
- import json from "@poppinss/utils/json";
2029
- import Macroable6 from "@poppinss/macroable";
2030
- import { createReadStream } from "node:fs";
2031
- import { stat } from "node:fs/promises";
2032
- import { RuntimeException as RuntimeException3 } from "@poppinss/utils";
2033
- import contentDisposition from "content-disposition";
2034
-
2035
- // src/cookies/serializer.ts
2036
- import cookie2 from "cookie";
2037
- import string2 from "@poppinss/utils/string";
2038
- var CookieSerializer = class {
2039
- #client;
2040
- constructor(encryption) {
2041
- this.#client = new CookieClient(encryption);
2042
- }
2043
- /**
2044
- * Serializes the key-value pair to a string, that can be set on the
2045
- * `Set-Cookie` header.
2046
- */
2047
- #serializeAsCookie(key, value, options) {
2048
- let expires = options?.expires;
2049
- if (typeof expires === "function") {
2050
- expires = expires();
2051
- }
2052
- let maxAge = options?.maxAge ? string2.seconds.parse(options?.maxAge) : void 0;
2053
- const parsedOptions = Object.assign({}, options, { maxAge, expires });
2054
- return cookie2.serialize(key, value, parsedOptions);
2055
- }
2056
- /**
2057
- * Encodes value as a plain cookie. By default, the plain value will be converted
2058
- * to a string using "JSON.stringify" method and then encoded as a base64 string.
2059
- *
2060
- * You can disable encoding of the cookie by setting `options.encoded = false`.
2061
- *
2062
- * ```ts
2063
- * serializer.encode('name', 'virk')
2064
- * ```
2065
- */
2066
- encode(key, value, options) {
2067
- const packedValue = options?.encode === false ? value : this.#client.encode(key, value);
2068
- if (packedValue === null || packedValue === void 0) {
2069
- return null;
2070
- }
2071
- return this.#serializeAsCookie(key, packedValue, options);
2072
- }
2073
- /**
2074
- * Sign a key-value pair to a signed cookie. The signed value has a
2075
- * verification hash attached to it to detect data tampering.
2076
- */
2077
- sign(key, value, options) {
2078
- const packedValue = this.#client.sign(key, value);
2079
- if (packedValue === null) {
2080
- return null;
2081
- }
2082
- return this.#serializeAsCookie(key, packedValue, options);
2083
- }
2084
- /**
2085
- * Encrypts a key-value pair to an encrypted cookie.
2086
- */
2087
- encrypt(key, value, options) {
2088
- const packedValue = this.#client.encrypt(key, value);
2089
- if (packedValue === null) {
2090
- return null;
2091
- }
2092
- return this.#serializeAsCookie(key, packedValue, options);
2093
- }
2094
- };
2095
-
2096
- // src/response.ts
2097
- var CACHEABLE_HTTP_METHODS = ["GET", "HEAD"];
2098
- var Response = class extends Macroable6 {
2099
- constructor(request, response, encryption, config, router, qs) {
2100
- super();
2101
- this.request = request;
2102
- this.response = response;
2103
- this.#qs = qs;
2104
- this.#config = config;
2105
- this.#router = router;
2106
- this.#cookieSerializer = new CookieSerializer(encryption);
2107
- }
2108
- /**
2109
- * Query string parser
2110
- */
2111
- #qs;
2112
- /**
2113
- * Outgoing headers
2114
- */
2115
- #headers = {};
2116
- /**
2117
- * Has explicit status been set
2118
- */
2119
- #hasExplicitStatus = false;
2120
- /**
2121
- * Cookies serializer to serialize the outgoing cookies
2122
- */
2123
- #cookieSerializer;
2124
- /**
2125
- * Router is used to make the redirect URLs from routes
2126
- */
2127
- #router;
2128
- /**
2129
- * Response config
2130
- */
2131
- #config;
2132
- /**
2133
- * Does response has body set that will written to the
2134
- * response socket at the end of the request
2135
- */
2136
- get hasLazyBody() {
2137
- return !!(this.lazyBody.content || this.lazyBody.fileToStream || this.lazyBody.stream);
2138
- }
2139
- /**
2140
- * Find if the response has non-stream content
2141
- */
2142
- get hasContent() {
2143
- return !!this.lazyBody.content;
2144
- }
2145
- /**
2146
- * Returns true when response body is set using "response.stream"
2147
- * method
2148
- */
2149
- get hasStream() {
2150
- return !!this.lazyBody.stream;
2151
- }
2152
- /**
2153
- * Returns true when response body is set using "response.download"
2154
- * or "response.attachment" methods
2155
- */
2156
- get hasFileToStream() {
2157
- return !!this.lazyBody.fileToStream;
2158
- }
2159
- /**
2160
- * Returns the response content. Check if the response
2161
- * has content using the "hasContent" method
2162
- */
2163
- get content() {
2164
- return this.lazyBody.content;
2165
- }
2166
- /**
2167
- * Returns reference to the stream set using "response.stream"
2168
- * method
2169
- */
2170
- get outgoingStream() {
2171
- return this.lazyBody.stream?.[0];
2172
- }
2173
- /**
2174
- * Returns reference to the file path set using "response.stream"
2175
- * method.
2176
- */
2177
- get fileToStream() {
2178
- return this.lazyBody.fileToStream ? {
2179
- path: this.lazyBody.fileToStream[0],
2180
- generateEtag: this.lazyBody.fileToStream[1]
2181
- } : void 0;
2182
- }
2183
- /**
2184
- * Lazy body is used to set the response body. However, do not
2185
- * write it on the socket immediately unless `response.finish`
2186
- * is called.
2187
- */
2188
- lazyBody = {};
2189
- /**
2190
- * The ctx will be set by the context itself. It creates a circular
2191
- * reference
2192
- */
2193
- ctx;
2194
- /**
2195
- * Returns a boolean telling if response is finished or not.
2196
- * Any more attempts to update headers or body will result
2197
- * in raised exceptions.
2198
- */
2199
- get finished() {
2200
- return this.response.writableFinished;
2201
- }
2202
- /**
2203
- * Returns a boolean telling if response headers has been sent or not.
2204
- * Any more attempts to update headers will result in raised
2205
- * exceptions.
2206
- */
2207
- get headersSent() {
2208
- return this.response.headersSent;
2209
- }
2210
- /**
2211
- * Returns a boolean telling if response headers and body is written
2212
- * or not. When value is `true`, you can feel free to write headers
2213
- * and body.
2214
- */
2215
- get isPending() {
2216
- return !this.headersSent && !this.finished;
2217
- }
2218
- /**
2219
- * Normalizes header value to a string or an array of string
2220
- */
2221
- #castHeaderValue(value) {
2222
- return Array.isArray(value) ? value.map(String) : String(value);
2223
- }
2224
- /**
2225
- * Ends the response by flushing headers and writing body
2226
- */
2227
- #endResponse(body, statusCode) {
2228
- this.writeHead(statusCode);
2229
- const res = this.response;
2230
- res.end(body, null, null);
2231
- }
2232
- /**
2233
- * Returns type for the content body. Only following types are allowed
2234
- *
2235
- * - Dates
2236
- * - Arrays
2237
- * - Booleans
2238
- * - Objects
2239
- * - Strings
2240
- * - Buffer
2241
- */
2242
- #getDataType(content) {
2243
- if (Buffer.isBuffer(content)) {
2244
- return "buffer";
2245
- }
2246
- if (content instanceof Date) {
2247
- return "date";
2248
- }
2249
- if (content instanceof RegExp) {
2250
- return "regexp";
2251
- }
2252
- const dataType = typeof content;
2253
- if (dataType === "number" || dataType === "boolean" || dataType === "string" || dataType === "bigint") {
2254
- return dataType;
2255
- }
2256
- if (dataType === "object") {
2257
- return "object";
2258
- }
2259
- throw new RuntimeException3(`Cannot serialize "${dataType}" to HTTP response`);
2260
- }
2261
- /**
2262
- * Writes the body with appropriate response headers. Etag header is set
2263
- * when `generateEtag` is set to `true`.
2264
- *
2265
- * Empty body results in `204`.
2266
- */
2267
- writeBody(content, generateEtag, jsonpCallbackName) {
2268
- const hasEmptyBody = content === null || content === void 0 || content === "";
2269
- if (hasEmptyBody) {
2270
- this.safeStatus(204);
2271
- }
2272
- const statusCode = this.response.statusCode;
2273
- if (statusCode && (statusCode < 200 || statusCode === 204 || statusCode === 304)) {
2274
- this.removeHeader("Content-Type");
2275
- this.removeHeader("Content-Length");
2276
- this.removeHeader("Transfer-Encoding");
2277
- this.#endResponse();
2278
- return;
2279
- }
2280
- if (hasEmptyBody) {
2281
- this.removeHeader("Content-Length");
2282
- this.#endResponse();
2283
- return;
2284
- }
2285
- const dataType = this.#getDataType(content);
2286
- if (dataType === "object") {
2287
- content = json.safeStringify(content);
2288
- } else if (dataType === "number" || dataType === "boolean" || dataType === "bigint" || dataType === "regexp") {
2289
- content = String(content);
2290
- } else if (dataType === "date") {
2291
- content = content.toISOString();
2292
- }
2293
- if (jsonpCallbackName) {
2294
- content = content.replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
2295
- content = `/**/ typeof ${jsonpCallbackName} === 'function' && ${jsonpCallbackName}(${content});`;
2296
- }
2297
- if (generateEtag) {
2298
- this.setEtag(content);
2299
- }
2300
- if (generateEtag && this.fresh()) {
2301
- this.removeHeader("Content-Type");
2302
- this.removeHeader("Content-Length");
2303
- this.removeHeader("Transfer-Encoding");
2304
- this.#endResponse(null, 304);
2305
- return;
2306
- }
2307
- this.header("Content-Length", Buffer.byteLength(content));
2308
- if (jsonpCallbackName) {
2309
- this.header("X-Content-Type-Options", "nosniff");
2310
- this.safeHeader("Content-Type", "text/javascript; charset=utf-8");
2311
- } else {
2312
- switch (dataType) {
2313
- case "string":
2314
- const type = /^\s*</.test(content) ? "text/html" : "text/plain";
2315
- this.safeHeader("Content-Type", `${type}; charset=utf-8`);
2316
- break;
2317
- case "number":
2318
- case "boolean":
2319
- case "date":
2320
- case "bigint":
2321
- case "regexp":
2322
- this.safeHeader("Content-Type", "text/plain; charset=utf-8");
2323
- break;
2324
- case "buffer":
2325
- this.safeHeader("Content-Type", "application/octet-stream; charset=utf-8");
2326
- break;
2327
- case "object":
2328
- this.safeHeader("Content-Type", "application/json; charset=utf-8");
2329
- break;
2330
- }
2331
- }
2332
- this.#endResponse(content);
2333
- }
2334
- /**
2335
- * Stream the body to the response and handles cleaning up the stream
2336
- */
2337
- streamBody(body, errorCallback) {
2338
- return new Promise((resolve) => {
2339
- let finished = false;
2340
- body.on("error", (error) => {
2341
- if (finished) {
2342
- return;
2343
- }
2344
- finished = true;
2345
- destroy(body);
2346
- this.type("text");
2347
- if (!this.headersSent) {
2348
- if (typeof errorCallback === "function") {
2349
- this.#endResponse(...errorCallback(error));
2350
- } else {
2351
- this.#endResponse(
2352
- error.code === "ENOENT" ? "File not found" : "Cannot process file",
2353
- error.code === "ENOENT" ? 404 : 500
2354
- );
2355
- }
2356
- } else {
2357
- this.response.destroy();
2358
- }
2359
- resolve();
2360
- });
2361
- body.on("end", () => {
2362
- if (!this.headersSent) {
2363
- this.#endResponse();
2364
- }
2365
- resolve();
2366
- });
2367
- onFinished(this.response, () => {
2368
- finished = true;
2369
- destroy(body);
2370
- });
2371
- this.relayHeaders();
2372
- body.pipe(this.response);
2373
- });
2374
- }
2375
- /**
2376
- * Downloads a file by streaming it to the response
2377
- */
2378
- async streamFileForDownload(filePath, generateEtag, errorCallback) {
2379
- try {
2380
- const stats = await stat(filePath);
2381
- if (!stats || !stats.isFile()) {
2382
- throw new TypeError("response.download only accepts path to a file");
2383
- }
2384
- this.header("Last-Modified", stats.mtime.toUTCString());
2385
- this.type(extname(filePath));
2386
- if (generateEtag) {
2387
- this.setEtag(stats, true);
2388
- }
2389
- if (this.request.method === "HEAD") {
2390
- this.#endResponse(null, generateEtag && this.fresh() ? 304 : 200);
2391
- return;
2392
- }
2393
- if (generateEtag && this.fresh()) {
2394
- this.#endResponse(null, 304);
2395
- return;
2396
- }
2397
- this.header("Content-length", stats.size);
2398
- return this.streamBody(createReadStream(filePath), errorCallback);
2399
- } catch (error) {
2400
- this.type("text");
2401
- this.removeHeader("Etag");
2402
- if (typeof errorCallback === "function") {
2403
- this.#endResponse(...errorCallback(error));
2404
- } else {
2405
- this.#endResponse(
2406
- error.code === "ENOENT" ? "File not found" : "Cannot process file",
2407
- error.code === "ENOENT" ? 404 : 500
2408
- );
2409
- }
2410
- }
2411
- }
2412
- /**
2413
- * Writes headers with the Node.js res object using the
2414
- * response.setHeader method
2415
- */
2416
- relayHeaders() {
2417
- if (!this.headersSent) {
2418
- for (let key in this.#headers) {
2419
- const value = this.#headers[key];
2420
- if (value) {
2421
- this.response.setHeader(key, value);
2422
- }
2423
- }
2424
- }
2425
- }
2426
- /**
2427
- * Calls res.writeHead on the Node.js res object.
2428
- */
2429
- writeHead(statusCode) {
2430
- this.response.writeHead(statusCode || this.response.statusCode, this.#headers);
2431
- return this;
2432
- }
2433
- /**
2434
- * Returns the existing value for a given HTTP response
2435
- * header.
2436
- */
2437
- getHeader(key) {
2438
- const value = this.#headers[key.toLowerCase()];
2439
- return value === void 0 ? this.response.getHeader(key) : value;
2440
- }
2441
- /**
2442
- * Get response headers
2443
- */
2444
- getHeaders() {
2445
- return {
2446
- ...this.response.getHeaders(),
2447
- ...this.#headers
2448
- };
2449
- }
2450
- /**
2451
- * Set header on the response. To `append` values to the existing header, we suggest
2452
- * using [[append]] method.
2453
- *
2454
- * If `value` is non existy, then header won't be set.
2455
- *
2456
- * @example
2457
- * ```js
2458
- * response.header('content-type', 'application/json')
2459
- * ```
2460
- */
2461
- header(key, value) {
2462
- if (value === null || value === void 0) {
2463
- return this;
2464
- }
2465
- this.#headers[key.toLowerCase()] = this.#castHeaderValue(value);
2466
- return this;
2467
- }
2468
- /**
2469
- * Append value to an existing header. To replace the value, we suggest using
2470
- * [[header]] method.
2471
- *
2472
- * If `value` is not existy, then header won't be set.
2473
- *
2474
- * @example
2475
- * ```js
2476
- * response.append('set-cookie', 'username=virk')
2477
- * ```
2478
- */
2479
- append(key, value) {
2480
- if (value === null || value === void 0) {
2481
- return this;
2482
- }
2483
- key = key.toLowerCase();
2484
- let existingHeader = this.getHeader(key);
2485
- let casted = this.#castHeaderValue(value);
2486
- if (!existingHeader) {
2487
- this.#headers[key] = casted;
2488
- return this;
2489
- }
2490
- existingHeader = this.#castHeaderValue(existingHeader);
2491
- casted = Array.isArray(existingHeader) ? existingHeader.concat(casted) : [existingHeader].concat(casted);
2492
- this.#headers[key] = casted;
2493
- return this;
2494
- }
2495
- /**
2496
- * Adds HTTP response header, when it doesn't exists already.
2497
- */
2498
- safeHeader(key, value) {
2499
- if (!this.getHeader(key)) {
2500
- this.header(key, value);
2501
- }
2502
- return this;
2503
- }
2504
- /**
2505
- * Removes the existing response header from being sent.
2506
- */
2507
- removeHeader(key) {
2508
- key = key.toLowerCase();
2509
- this.response.removeHeader(key);
2510
- if (this.#headers[key]) {
2511
- delete this.#headers[key.toLowerCase()];
2512
- }
2513
- return this;
2514
- }
2515
- /**
2516
- * Returns the status code for the response
2517
- */
2518
- getStatus() {
2519
- return this.response.statusCode;
2520
- }
2521
- /**
2522
- * Set HTTP status code
2523
- */
2524
- status(code) {
2525
- this.#hasExplicitStatus = true;
2526
- this.response.statusCode = code;
2527
- return this;
2528
- }
2529
- /**
2530
- * Set's status code only when it's not explictly
2531
- * set
2532
- */
2533
- safeStatus(code) {
2534
- if (this.#hasExplicitStatus) {
2535
- return this;
2536
- }
2537
- this.response.statusCode = code;
2538
- return this;
2539
- }
2540
- /**
2541
- * Set response type by looking up for the mime-type using
2542
- * partial types like file extensions.
2543
- *
2544
- * Make sure to read [mime-types](https://www.npmjs.com/package/mime-types) docs
2545
- * too.
2546
- *
2547
- * @example
2548
- * ```js
2549
- * response.type('.json') // Content-type: application/json
2550
- * ```
2551
- */
2552
- type(type, charset) {
2553
- type = charset ? `${type}; charset=${charset}` : type;
2554
- this.header("Content-Type", mime.contentType(type));
2555
- return this;
2556
- }
2557
- /**
2558
- * Set the Vary HTTP header
2559
- */
2560
- vary(field) {
2561
- vary(this.response, field);
2562
- return this;
2563
- }
2564
- /**
2565
- * Set etag by computing hash from the body. This class will set the etag automatically
2566
- * when `etag = true` in the defined config object.
2567
- *
2568
- * Use this function, when you want to compute etag manually for some other resons.
2569
- */
2570
- setEtag(body, weak = false) {
2571
- this.header("Etag", etag(body, { weak }));
2572
- return this;
2573
- }
2574
- /**
2575
- * Returns a boolean telling if the new response etag evaluates same
2576
- * as the request header `if-none-match`. In case of `true`, the
2577
- * server must return `304` response, telling the browser to
2578
- * use the client cache.
2579
- *
2580
- * You won't have to deal with this method directly, since AdonisJs will
2581
- * handle this for you when `http.etag = true` inside `config/app.js` file.
2582
- *
2583
- * However, this is how you can use it manually.
2584
- *
2585
- * @example
2586
- * ```js
2587
- * const responseBody = view.render('some-view')
2588
- *
2589
- * // sets the HTTP etag header for response
2590
- * response.setEtag(responseBody)
2591
- *
2592
- * if (response.fresh()) {
2593
- * response.sendStatus(304)
2594
- * } else {
2595
- * response.send(responseBody)
2596
- * }
2597
- * ```
2598
- */
2599
- fresh() {
2600
- if (this.request.method && !CACHEABLE_HTTP_METHODS.includes(this.request.method)) {
2601
- return false;
2602
- }
2603
- const status = this.response.statusCode;
2604
- if (status >= 200 && status < 300 || status === 304) {
2605
- return fresh2(this.request.headers, this.#headers);
2606
- }
2607
- return false;
2608
- }
2609
- /**
2610
- * Returns the response body. Returns null when response
2611
- * body is a stream
2612
- */
2613
- getBody() {
2614
- if (this.lazyBody.content) {
2615
- return this.lazyBody.content[0];
2616
- }
2617
- return null;
2618
- }
2619
- /**
2620
- * Send the body as response and optionally generate etag. The default value
2621
- * is read from `config/app.js` file, using `http.etag` property.
2622
- *
2623
- * This method buffers the body if `explicitEnd = true`, which is the default
2624
- * behavior and do not change, unless you know what you are doing.
2625
- */
2626
- send(body, generateEtag = this.#config.etag) {
2627
- this.lazyBody.content = [body, generateEtag];
2628
- }
2629
- /**
2630
- * Alias of [[send]]
2631
- */
2632
- json(body, generateEtag = this.#config.etag) {
2633
- return this.send(body, generateEtag);
2634
- }
2635
- /**
2636
- * Writes response as JSONP. The callback name is resolved as follows, with priority
2637
- * from top to bottom.
2638
- *
2639
- * 1. Explicitly defined as 2nd Param.
2640
- * 2. Fetch from request query string.
2641
- * 3. Use the config value `http.jsonpCallbackName` from `config/app.js`.
2642
- * 4. Fallback to `callback`.
2643
- *
2644
- * This method buffers the body if `explicitEnd = true`, which is the default
2645
- * behavior and do not change, unless you know what you are doing.
2646
- */
2647
- jsonp(body, callbackName = this.#config.jsonpCallbackName, generateEtag = this.#config.etag) {
2648
- this.lazyBody.content = [body, generateEtag, callbackName];
2649
- }
2650
- /**
2651
- * Pipe stream to the response. This method will gracefully destroy
2652
- * the stream, avoiding memory leaks.
2653
- *
2654
- * If `raiseErrors=false`, then this method will self handle all the exceptions by
2655
- * writing a generic HTTP response. To have more control over the error, it is
2656
- * recommended to set `raiseErrors=true` and wrap this function inside a
2657
- * `try/catch` statement.
2658
- *
2659
- * Streaming a file from the disk and showing 404 when file is missing.
2660
- *
2661
- * @example
2662
- * ```js
2663
- * // Errors handled automatically with generic HTTP response
2664
- * response.stream(fs.createReadStream('file.txt'))
2665
- *
2666
- * // Manually handle (note the await call)
2667
- * try {
2668
- * await response.stream(fs.createReadStream('file.txt'))
2669
- * } catch () {
2670
- * response.status(404).send('File not found')
2671
- * }
2672
- * ```
2673
- */
2674
- stream(body, errorCallback) {
2675
- if (typeof body.pipe !== "function" || !body.readable || typeof body.read !== "function") {
2676
- throw new TypeError("response.stream accepts a readable stream only");
2677
- }
2678
- this.lazyBody.stream = [body, errorCallback];
2679
- }
2680
- /**
2681
- * Download file by streaming it from the file path. This method will setup
2682
- * appropriate `Content-type`, `Content-type` and `Last-modified` headers.
2683
- *
2684
- * Unexpected stream errors are handled gracefully to avoid memory leaks.
2685
- *
2686
- * If `raiseErrors=false`, then this method will self handle all the exceptions by
2687
- * writing a generic HTTP response. To have more control over the error, it is
2688
- * recommended to set `raiseErrors=true` and wrap this function inside a
2689
- * `try/catch` statement.
2690
- *
2691
- * @example
2692
- * ```js
2693
- * // Errors handled automatically with generic HTTP response
2694
- * response.download('somefile.jpg')
2695
- *
2696
- * // Manually handle (note the await call)
2697
- * try {
2698
- * await response.download('somefile.jpg')
2699
- * } catch (error) {
2700
- * response.status(error.code === 'ENOENT' ? 404 : 500)
2701
- * response.send('Cannot process file')
2702
- * }
2703
- * ```
2704
- */
2705
- download(filePath, generateEtag = this.#config.etag, errorCallback) {
2706
- this.lazyBody.fileToStream = [filePath, generateEtag, errorCallback];
2707
- }
2708
- /**
2709
- * Download the file by forcing the user to save the file vs displaying it
2710
- * within the browser.
2711
- *
2712
- * Internally calls [[download]]
2713
- */
2714
- attachment(filePath, name, disposition, generateEtag, errorCallback) {
2715
- name = name || filePath;
2716
- this.header("Content-Disposition", contentDisposition(name, { type: disposition }));
2717
- return this.download(filePath, generateEtag, errorCallback);
2718
- }
2719
- /**
2720
- * Set the location header.
2721
- *
2722
- * @example
2723
- * ```js
2724
- * response.location('/login')
2725
- * ```
2726
- */
2727
- location(url) {
2728
- this.header("Location", url);
2729
- return this;
2730
- }
2731
- redirect(path, forwardQueryString = false, statusCode = 302) {
2732
- const handler = new Redirect(this.request, this, this.#router, this.#qs);
2733
- if (forwardQueryString) {
2734
- handler.withQs();
2735
- }
2736
- if (path === "back") {
2737
- return handler.status(statusCode).back();
2738
- }
2739
- if (path) {
2740
- return handler.status(statusCode).toPath(path);
2741
- }
2742
- return handler;
2743
- }
2744
- /**
2745
- * Abort the request with custom body and a status code. 400 is
2746
- * used when status is not defined
2747
- */
2748
- abort(body, status) {
2749
- throw E_HTTP_REQUEST_ABORTED.invoke(body, status || 400);
2750
- }
2751
- /**
2752
- * Abort the request with custom body and a status code when
2753
- * passed condition returns `true`
2754
- */
2755
- abortIf(condition, body, status) {
2756
- if (condition) {
2757
- this.abort(body, status);
2758
- }
2759
- }
2760
- /**
2761
- * Abort the request with custom body and a status code when
2762
- * passed condition returns `false`
2763
- */
2764
- abortUnless(condition, body, status) {
2765
- if (!condition) {
2766
- this.abort(body, status);
2767
- }
2768
- }
2769
- /**
2770
- * Set signed cookie as the response header. The inline options overrides
2771
- * all options from the config.
2772
- */
2773
- cookie(key, value, options) {
2774
- options = Object.assign({}, this.#config.cookie, options);
2775
- const serialized = this.#cookieSerializer.sign(key, value, options);
2776
- if (!serialized) {
2777
- return this;
2778
- }
2779
- this.append("set-cookie", serialized);
2780
- return this;
2781
- }
2782
- /**
2783
- * Set encrypted cookie as the response header. The inline options overrides
2784
- * all options from the config.
2785
- */
2786
- encryptedCookie(key, value, options) {
2787
- options = Object.assign({}, this.#config.cookie, options);
2788
- const serialized = this.#cookieSerializer.encrypt(key, value, options);
2789
- if (!serialized) {
2790
- return this;
2791
- }
2792
- this.append("set-cookie", serialized);
2793
- return this;
2794
- }
2795
- /**
2796
- * Set unsigned cookie as the response header. The inline options overrides
2797
- * all options from the config.
2798
- */
2799
- plainCookie(key, value, options) {
2800
- options = Object.assign({}, this.#config.cookie, options);
2801
- const serialized = this.#cookieSerializer.encode(key, value, options);
2802
- if (!serialized) {
2803
- return this;
2804
- }
2805
- this.append("set-cookie", serialized);
2806
- return this;
2807
- }
2808
- /**
2809
- * Clear existing cookie.
2810
- */
2811
- clearCookie(key, options) {
2812
- options = Object.assign({}, this.#config.cookie, options);
2813
- options.expires = /* @__PURE__ */ new Date(1);
2814
- options.maxAge = -1;
2815
- const serialized = this.#cookieSerializer.encode(key, "", { ...options, encode: false });
2816
- this.append("set-cookie", serialized);
2817
- return this;
2818
- }
2819
- /**
2820
- * Finishes the response by writing the lazy body, when `explicitEnd = true`
2821
- * and response is already pending.
2822
- *
2823
- * Calling this method twice or when `explicitEnd = false` is noop.
2824
- */
2825
- finish() {
2826
- if (!this.isPending) {
2827
- return;
2828
- }
2829
- if (this.content) {
2830
- this.writeBody(...this.content);
2831
- return;
2832
- }
2833
- if (this.lazyBody.stream) {
2834
- this.streamBody(...this.lazyBody.stream);
2835
- return;
2836
- }
2837
- if (this.lazyBody.fileToStream) {
2838
- this.streamFileForDownload(...this.lazyBody.fileToStream);
2839
- return;
2840
- }
2841
- this.#endResponse();
2842
- }
2843
- /**
2844
- * Shorthand method to finish request with "100" status code
2845
- */
2846
- continue() {
2847
- this.status(100);
2848
- return this.send(null, false);
2849
- }
2850
- /**
2851
- * Shorthand method to finish request with "101" status code
2852
- */
2853
- switchingProtocols() {
2854
- this.status(101);
2855
- return this.send(null, false);
2856
- }
2857
- /**
2858
- * Shorthand method to finish request with "200" status code
2859
- */
2860
- ok(body, generateEtag) {
2861
- this.status(200);
2862
- return this.send(body, generateEtag);
2863
- }
2864
- /**
2865
- * Shorthand method to finish request with "201" status code
2866
- */
2867
- created(body, generateEtag) {
2868
- this.status(201);
2869
- return this.send(body, generateEtag);
2870
- }
2871
- /**
2872
- * Shorthand method to finish request with "202" status code
2873
- */
2874
- accepted(body, generateEtag) {
2875
- this.status(202);
2876
- return this.send(body, generateEtag);
2877
- }
2878
- /**
2879
- * Shorthand method to finish request with "203" status code
2880
- */
2881
- nonAuthoritativeInformation(body, generateEtag) {
2882
- this.status(203);
2883
- return this.send(body, generateEtag);
2884
- }
2885
- /**
2886
- * Shorthand method to finish request with "204" status code
2887
- */
2888
- noContent() {
2889
- this.status(204);
2890
- return this.send(null, false);
2891
- }
2892
- /**
2893
- * Shorthand method to finish request with "205" status code
2894
- */
2895
- resetContent() {
2896
- this.status(205);
2897
- return this.send(null, false);
2898
- }
2899
- /**
2900
- * Shorthand method to finish request with "206" status code
2901
- */
2902
- partialContent(body, generateEtag) {
2903
- this.status(206);
2904
- return this.send(body, generateEtag);
2905
- }
2906
- /**
2907
- * Shorthand method to finish request with "300" status code
2908
- */
2909
- multipleChoices(body, generateEtag) {
2910
- this.status(300);
2911
- return this.send(body, generateEtag);
2912
- }
2913
- /**
2914
- * Shorthand method to finish request with "301" status code
2915
- */
2916
- movedPermanently(body, generateEtag) {
2917
- this.status(301);
2918
- return this.send(body, generateEtag);
2919
- }
2920
- /**
2921
- * Shorthand method to finish request with "302" status code
2922
- */
2923
- movedTemporarily(body, generateEtag) {
2924
- this.status(302);
2925
- return this.send(body, generateEtag);
2926
- }
2927
- /**
2928
- * Shorthand method to finish request with "303" status code
2929
- */
2930
- seeOther(body, generateEtag) {
2931
- this.status(303);
2932
- return this.send(body, generateEtag);
2933
- }
2934
- /**
2935
- * Shorthand method to finish request with "304" status code
2936
- */
2937
- notModified(body, generateEtag) {
2938
- this.status(304);
2939
- return this.send(body, generateEtag);
2940
- }
2941
- /**
2942
- * Shorthand method to finish request with "305" status code
2943
- */
2944
- useProxy(body, generateEtag) {
2945
- this.status(305);
2946
- return this.send(body, generateEtag);
2947
- }
2948
- /**
2949
- * Shorthand method to finish request with "307" status code
2950
- */
2951
- temporaryRedirect(body, generateEtag) {
2952
- this.status(307);
2953
- return this.send(body, generateEtag);
2954
- }
2955
- /**
2956
- * Shorthand method to finish request with "400" status code
2957
- */
2958
- badRequest(body, generateEtag) {
2959
- this.status(400);
2960
- return this.send(body, generateEtag);
2961
- }
2962
- /**
2963
- * Shorthand method to finish request with "401" status code
2964
- */
2965
- unauthorized(body, generateEtag) {
2966
- this.status(401);
2967
- return this.send(body, generateEtag);
2968
- }
2969
- /**
2970
- * Shorthand method to finish request with "402" status code
2971
- */
2972
- paymentRequired(body, generateEtag) {
2973
- this.status(402);
2974
- return this.send(body, generateEtag);
2975
- }
2976
- /**
2977
- * Shorthand method to finish request with "403" status code
2978
- */
2979
- forbidden(body, generateEtag) {
2980
- this.status(403);
2981
- return this.send(body, generateEtag);
2982
- }
2983
- /**
2984
- * Shorthand method to finish request with "404" status code
2985
- */
2986
- notFound(body, generateEtag) {
2987
- this.status(404);
2988
- return this.send(body, generateEtag);
2989
- }
2990
- /**
2991
- * Shorthand method to finish request with "405" status code
2992
- */
2993
- methodNotAllowed(body, generateEtag) {
2994
- this.status(405);
2995
- return this.send(body, generateEtag);
2996
- }
2997
- /**
2998
- * Shorthand method to finish request with "406" status code
2999
- */
3000
- notAcceptable(body, generateEtag) {
3001
- this.status(406);
3002
- return this.send(body, generateEtag);
3003
- }
3004
- /**
3005
- * Shorthand method to finish request with "407" status code
3006
- */
3007
- proxyAuthenticationRequired(body, generateEtag) {
3008
- this.status(407);
3009
- return this.send(body, generateEtag);
3010
- }
3011
- /**
3012
- * Shorthand method to finish request with "408" status code
3013
- */
3014
- requestTimeout(body, generateEtag) {
3015
- this.status(408);
3016
- return this.send(body, generateEtag);
3017
- }
3018
- /**
3019
- * Shorthand method to finish request with "409" status code
3020
- */
3021
- conflict(body, generateEtag) {
3022
- this.status(409);
3023
- return this.send(body, generateEtag);
3024
- }
3025
- /**
3026
- * Shorthand method to finish request with "401" status code
3027
- */
3028
- gone(body, generateEtag) {
3029
- this.status(410);
3030
- return this.send(body, generateEtag);
3031
- }
3032
- /**
3033
- * Shorthand method to finish request with "411" status code
3034
- */
3035
- lengthRequired(body, generateEtag) {
3036
- this.status(411);
3037
- return this.send(body, generateEtag);
3038
- }
3039
- /**
3040
- * Shorthand method to finish request with "412" status code
3041
- */
3042
- preconditionFailed(body, generateEtag) {
3043
- this.status(412);
3044
- return this.send(body, generateEtag);
3045
- }
3046
- /**
3047
- * Shorthand method to finish request with "413" status code
3048
- */
3049
- requestEntityTooLarge(body, generateEtag) {
3050
- this.status(413);
3051
- return this.send(body, generateEtag);
3052
- }
3053
- /**
3054
- * Shorthand method to finish request with "414" status code
3055
- */
3056
- requestUriTooLong(body, generateEtag) {
3057
- this.status(414);
3058
- return this.send(body, generateEtag);
3059
- }
3060
- /**
3061
- * Shorthand method to finish request with "415" status code
3062
- */
3063
- unsupportedMediaType(body, generateEtag) {
3064
- this.status(415);
3065
- return this.send(body, generateEtag);
3066
- }
3067
- /**
3068
- * Shorthand method to finish request with "416" status code
3069
- */
3070
- requestedRangeNotSatisfiable(body, generateEtag) {
3071
- this.status(416);
3072
- return this.send(body, generateEtag);
3073
- }
3074
- /**
3075
- * Shorthand method to finish request with "417" status code
3076
- */
3077
- expectationFailed(body, generateEtag) {
3078
- this.status(417);
3079
- return this.send(body, generateEtag);
3080
- }
3081
- /**
3082
- * Shorthand method to finish request with "422" status code
3083
- */
3084
- unprocessableEntity(body, generateEtag) {
3085
- this.status(422);
3086
- return this.send(body, generateEtag);
3087
- }
3088
- /**
3089
- * Shorthand method to finish request with "429" status code
3090
- */
3091
- tooManyRequests(body, generateEtag) {
3092
- this.status(429);
3093
- return this.send(body, generateEtag);
3094
- }
3095
- /**
3096
- * Shorthand method to finish request with "500" status code
3097
- */
3098
- internalServerError(body, generateEtag) {
3099
- this.status(500);
3100
- return this.send(body, generateEtag);
3101
- }
3102
- /**
3103
- * Shorthand method to finish request with "501" status code
3104
- */
3105
- notImplemented(body, generateEtag) {
3106
- this.status(501);
3107
- return this.send(body, generateEtag);
3108
- }
3109
- /**
3110
- * Shorthand method to finish request with "502" status code
3111
- */
3112
- badGateway(body, generateEtag) {
3113
- this.status(502);
3114
- return this.send(body, generateEtag);
3115
- }
3116
- /**
3117
- * Shorthand method to finish request with "503" status code
3118
- */
3119
- serviceUnavailable(body, generateEtag) {
3120
- this.status(503);
3121
- return this.send(body, generateEtag);
3122
- }
3123
- /**
3124
- * Shorthand method to finish request with "504" status code
3125
- */
3126
- gatewayTimeout(body, generateEtag) {
3127
- this.status(504);
3128
- return this.send(body, generateEtag);
3129
- }
3130
- /**
3131
- * Shorthand method to finish request with "505" status code
3132
- */
3133
- httpVersionNotSupported(body, generateEtag) {
3134
- this.status(505);
3135
- return this.send(body, generateEtag);
3136
- }
3137
- };
3138
-
3139
- // src/router/main.ts
3140
- import is3 from "@sindresorhus/is";
3141
- import { moduleImporter as moduleImporter3 } from "@adonisjs/fold";
3142
- import { RuntimeException as RuntimeException6 } from "@poppinss/utils";
3143
-
3144
- // src/router/store.ts
3145
- import matchit2 from "@poppinss/matchit";
3146
- import lodash2 from "@poppinss/utils/lodash";
3147
- import { RuntimeException as RuntimeException4 } from "@poppinss/utils";
3148
-
3149
- // src/router/parser.ts
3150
- import matchit from "@poppinss/matchit";
3151
- function parseRoutePattern(pattern, matchers) {
3152
- const tokens = matchit.parse(pattern, matchers);
3153
- return tokens;
3154
- }
3155
-
3156
- // src/router/store.ts
3157
- var RoutesStore = class {
3158
- /**
3159
- * A flag to know if routes for explicit domains
3160
- * have been registered
3161
- */
3162
- usingDomains = false;
3163
- /**
3164
- * Tree of registered routes and their matchit tokens
3165
- */
3166
- tree = { tokens: [], domains: {} };
3167
- /**
3168
- * Returns the domain node for a given domain.
3169
- */
3170
- #getDomainNode(domain) {
3171
- if (!this.tree.domains[domain]) {
3172
- this.tree.tokens.push(parseRoutePattern(domain));
3173
- this.tree.domains[domain] = {};
3174
- }
3175
- return this.tree.domains[domain];
3176
- }
3177
- /**
3178
- * Returns the method node for a given domain and method.
3179
- */
3180
- #getMethodNode(domain, method) {
3181
- const domainNode = this.#getDomainNode(domain);
3182
- if (!domainNode[method]) {
3183
- domainNode[method] = { tokens: [], routes: {}, routeKeys: {} };
3184
- }
3185
- return domainNode[method];
3186
- }
3187
- /**
3188
- * Collects route params
3189
- */
3190
- #collectRouteParams(route, tokens) {
3191
- const collectedParams = /* @__PURE__ */ new Set();
3192
- for (let token of tokens) {
3193
- if ([1, 3].includes(token.type)) {
3194
- if (collectedParams.has(token.val)) {
3195
- throw new RuntimeException4(`Duplicate param "${token.val}" found in "${route.pattern}"`);
3196
- } else {
3197
- collectedParams.add(token.val);
3198
- }
3199
- }
3200
- }
3201
- const params = [...collectedParams];
3202
- collectedParams.clear();
3203
- return params;
3204
- }
3205
- /**
3206
- * Register route for a given domain and method
3207
- */
3208
- #registerRoute(domain, method, tokens, route) {
3209
- const methodRoutes = this.#getMethodNode(domain, method);
3210
- if (methodRoutes.routes[route.pattern]) {
3211
- throw new RuntimeException4(
3212
- `Duplicate route found. "${method}: ${route.pattern}" route already exists`
3213
- );
3214
- }
3215
- if (debug_default.enabled) {
3216
- debug_default("registering route to the store %O", route);
3217
- debug_default("route middleware %O", route.middleware.all().entries());
3218
- }
3219
- methodRoutes.tokens.push(tokens);
3220
- methodRoutes.routes[route.pattern] = route;
3221
- methodRoutes.routeKeys[route.pattern] = domain !== "root" ? `${domain}-${method}-${route.pattern}` : `${method}-${route.pattern}`;
3222
- }
3223
- /**
3224
- * Add a route to the store
3225
- *
3226
- * ```ts
3227
- * store.add({
3228
- * pattern: 'post/:id',
3229
- * methods: ['GET'],
3230
- * matchers: {},
3231
- * meta: {},
3232
- * handler: function handler () {
3233
- * }
3234
- * })
3235
- * ```
3236
- */
3237
- add(route) {
3238
- if (route.domain !== "root") {
3239
- this.usingDomains = true;
3240
- }
3241
- const tokens = parseRoutePattern(route.pattern, route.matchers);
3242
- const routeNode = lodash2.merge(
3243
- { meta: {} },
3244
- lodash2.pick(route, ["pattern", "handler", "meta", "middleware", "name", "execute"])
3245
- );
3246
- routeNode.meta.params = this.#collectRouteParams(routeNode, tokens);
3247
- route.methods.forEach((method) => {
3248
- this.#registerRoute(route.domain, method, tokens, routeNode);
3249
- });
3250
- return this;
3251
- }
3252
- /**
3253
- * Matches the url, method and optionally domain to pull the matching
3254
- * route. `null` is returned when unable to match the URL against
3255
- * registered routes.
3256
- *
3257
- * The domain parameter has to be a registered pattern and not the fully
3258
- * qualified runtime domain. You must call `matchDomain` first to fetch
3259
- * the pattern for qualified domain
3260
- */
3261
- match(url, method, domain) {
3262
- const domainName = domain?.tokens[0]?.old || "root";
3263
- const matchedDomain = this.tree.domains[domainName];
3264
- if (!matchedDomain) {
3265
- return null;
3266
- }
3267
- const matchedMethod = this.tree.domains[domainName][method];
3268
- if (!matchedMethod) {
3269
- return null;
3270
- }
3271
- const matchedRoute = matchit2.match(url, matchedMethod.tokens);
3272
- if (!matchedRoute.length) {
3273
- return null;
3274
- }
3275
- const route = matchedMethod.routes[matchedRoute[0].old];
3276
- return {
3277
- route,
3278
- routeKey: matchedMethod.routeKeys[route.pattern],
3279
- params: matchit2.exec(url, matchedRoute),
3280
- subdomains: domain?.hostname ? matchit2.exec(domain.hostname, domain.tokens) : {}
3281
- };
3282
- }
3283
- /**
3284
- * Match hostname against registered domains.
3285
- */
3286
- matchDomain(hostname) {
3287
- if (!hostname || !this.usingDomains) {
3288
- return [];
3289
- }
3290
- return matchit2.match(hostname, this.tree.tokens);
3291
- }
3292
- };
3293
-
3294
- // src/router/lookup_store/url_builder.ts
3295
- import { RuntimeException as RuntimeException5 } from "@poppinss/utils";
3296
- var UrlBuilder = class {
3297
- /**
3298
- * Query string parser
3299
- */
3300
- #qsParser;
3301
- /**
3302
- * The parameters to apply on the route
3303
- */
3304
- #params = {};
3305
- /**
3306
- * Query string to append to the route
3307
- */
3308
- #qs = {};
3309
- /**
3310
- * Should we perform the route lookup or just build the
3311
- * given pattern as it is.
3312
- */
3313
- #shouldPerformLookup = true;
3314
- /**
3315
- * BaseURL to append to the constructored URL
3316
- */
3317
- #baseUrl;
3318
- /**
3319
- * Encryption class for making signed URLs
3320
- */
3321
- #encryption;
3322
- /**
3323
- * Route finder for finding route pattern
3324
- */
3325
- #routeFinder;
3326
- constructor(encryption, routeFinder, qsParser) {
3327
- this.#qsParser = qsParser;
3328
- this.#encryption = encryption;
3329
- this.#routeFinder = routeFinder;
3330
- }
3331
- /**
3332
- * Raises exception when wildcard values array is missing or
3333
- * has length of zero.
3334
- */
3335
- #ensureHasWildCardValues(pattern, values) {
3336
- if (!values || !Array.isArray(values) || !values.length) {
3337
- throw new RuntimeException5(
3338
- `Cannot make URL for "${pattern}" route. Invalid value provided for wildcard param`
3339
- );
3340
- }
3341
- }
3342
- /*
3343
- * Raises exception when value is not defined
3344
- */
3345
- #ensureHasParamValue(pattern, param, value) {
3346
- if (value === void 0 || value === null) {
3347
- throw new RuntimeException5(
3348
- `Cannot make URL for "${pattern}" route. Missing value for "${param}" param`
3349
- );
3350
- }
3351
- }
3352
- /**
3353
- * Processes the pattern against the params
3354
- */
3355
- #processPattern(pattern) {
3356
- const uriSegments = [];
3357
- const paramsArray = Array.isArray(this.#params) ? this.#params : null;
3358
- const paramsObject = !Array.isArray(this.#params) ? this.#params : {};
3359
- let paramsIndex = 0;
3360
- const tokens = parseRoutePattern(pattern);
3361
- for (const token of tokens) {
3362
- if (token.type === 0) {
3363
- uriSegments.push(`${token.val}${token.end}`);
3364
- } else if (token.type === 2) {
3365
- const values = paramsArray ? paramsArray.slice(paramsIndex) : paramsObject["*"];
3366
- this.#ensureHasWildCardValues(pattern, values);
3367
- uriSegments.push(`${values.join("/")}${token.end}`);
3368
- break;
3369
- } else {
3370
- const paramName = token.val;
3371
- const value = paramsArray ? paramsArray[paramsIndex] : paramsObject[paramName];
3372
- if (token.type === 1) {
3373
- this.#ensureHasParamValue(pattern, paramName, value);
3374
- }
3375
- paramsIndex++;
3376
- if (value !== void 0 && value !== null) {
3377
- uriSegments.push(`${value}${token.end}`);
3378
- }
3379
- }
3380
- }
3381
- return `/${uriSegments.join("/")}`;
3382
- }
3383
- /**
3384
- * Suffix the query string to the URL
3385
- */
3386
- #suffixQueryString(url, qs) {
3387
- if (qs) {
3388
- const queryString = this.#qsParser.stringify(qs);
3389
- url = queryString ? `${url}?${queryString}` : url;
3390
- }
3391
- return url;
3392
- }
3393
- /**
3394
- * Prefixes base URL to the uri string
3395
- */
3396
- #prefixBaseUrl(uri) {
3397
- return this.#baseUrl ? `${this.#baseUrl}${uri}` : uri;
3398
- }
3399
- /**
3400
- * Prefix a custom base URL to the final URI
3401
- */
3402
- prefixUrl(url) {
3403
- this.#baseUrl = url;
3404
- return this;
3405
- }
3406
- /**
3407
- * Disable route lookup. Calling this method considers
3408
- * the "identifier" as the route pattern
3409
- */
3410
- disableRouteLookup() {
3411
- this.#shouldPerformLookup = false;
3412
- return this;
3413
- }
3414
- /**
3415
- * Append query string to the final URI
3416
- */
3417
- qs(queryString) {
3418
- if (!queryString) {
3419
- return this;
3420
- }
3421
- this.#qs = queryString;
3422
- return this;
3423
- }
3424
- /**
3425
- * Specify params to apply to the route pattern
3426
- */
3427
- params(params) {
3428
- if (!params) {
3429
- return this;
3430
- }
3431
- this.#params = params;
3432
- return this;
3433
- }
3434
- /**
3435
- * Generate URL for the given route identifier. The identifier can be the
3436
- * route name, controller.method name or the route pattern
3437
- * itself.
3438
- */
3439
- make(identifier) {
3440
- let url;
3441
- if (this.#shouldPerformLookup) {
3442
- const route = this.#routeFinder.findOrFail(identifier);
3443
- url = this.#processPattern(route.pattern);
3444
- } else {
3445
- url = this.#processPattern(identifier);
3446
- }
3447
- return this.#suffixQueryString(this.#prefixBaseUrl(url), this.#qs);
3448
- }
3449
- /**
3450
- * Generate a signed URL for the given route identifier. The identifier can be the
3451
- * route name, controller.method name or the route pattern
3452
- * itself.
3453
- */
3454
- makeSigned(identifier, options) {
3455
- let url;
3456
- if (this.#shouldPerformLookup) {
3457
- const route = this.#routeFinder.findOrFail(identifier);
3458
- url = this.#processPattern(route.pattern);
3459
- } else {
3460
- url = this.#processPattern(identifier);
3461
- }
3462
- const signature = this.#encryption.verifier.sign(
3463
- this.#suffixQueryString(url, this.#qs),
3464
- options?.expiresIn,
3465
- options?.purpose
3466
- );
3467
- const qs = Object.assign({}, this.#qs, { signature });
3468
- return this.#suffixQueryString(this.#prefixBaseUrl(url), qs);
3469
- }
3470
- };
3471
-
3472
- // src/router/lookup_store/route_finder.ts
3473
- var RouteFinder = class {
3474
- #routes;
3475
- constructor(routes) {
3476
- this.#routes = routes;
3477
- }
3478
- /**
3479
- * Find a route by indentifier
3480
- */
3481
- find(routeIdentifier) {
3482
- return this.#routes.find(({ name, pattern, handler }) => {
3483
- if (name === routeIdentifier || pattern === routeIdentifier) {
3484
- return true;
3485
- }
3486
- if (typeof handler === "function") {
3487
- return false;
3488
- }
3489
- return handler.reference === routeIdentifier;
3490
- }) || null;
3491
- }
3492
- /**
3493
- * Find a route by indentifier or fail
3494
- */
3495
- findOrFail(routeIdentifier) {
3496
- const route = this.find(routeIdentifier);
3497
- if (!route) {
3498
- throw new E_CANNOT_LOOKUP_ROUTE([routeIdentifier]);
3499
- }
3500
- return route;
3501
- }
3502
- /**
3503
- * Find if a route exists
3504
- */
3505
- has(routeIdentifier) {
3506
- return !!this.find(routeIdentifier);
3507
- }
3508
- };
3509
-
3510
- // src/router/lookup_store/main.ts
3511
- var LookupStore = class {
3512
- /**
3513
- * List of routes grouped by domain
3514
- */
3515
- #routes = {};
3516
- /**
3517
- * Encryption for making URLs
3518
- */
3519
- #encryption;
3520
- /**
3521
- * Query string parser for making URLs
3522
- */
3523
- #qsParser;
3524
- constructor(encryption, qsParser) {
3525
- this.#encryption = encryption;
3526
- this.#qsParser = qsParser;
3527
- }
3528
- /**
3529
- * Register route JSON payload
3530
- */
3531
- register(route) {
3532
- this.#routes[route.domain] = this.#routes[route.domain] || [];
3533
- this.#routes[route.domain].push(route);
3534
- }
3535
- /**
3536
- * Returns an instance of the URL builder for making
3537
- * route URIs
3538
- */
3539
- builder() {
3540
- return this.builderForDomain("root");
3541
- }
3542
- /**
3543
- * Returns an instance of the URL builder for a specific
3544
- * domain.
3545
- */
3546
- builderForDomain(domain) {
3547
- const routes = this.#routes[domain];
3548
- return new UrlBuilder(this.#encryption, new RouteFinder(routes || []), this.#qsParser);
3549
- }
3550
- /**
3551
- * Finds a route by its identifier. The identifier can be the
3552
- * route name, controller.method name or the route pattern
3553
- * itself.
3554
- */
3555
- find(routeIdentifier, domain) {
3556
- const routes = this.#routes[domain || "root"] || [];
3557
- return new RouteFinder(routes).find(routeIdentifier);
3558
- }
3559
- /**
3560
- * Finds a route by its identifier. The identifier can be the
3561
- * route name, controller.method name or the route pattern
3562
- * itself.
3563
- *
3564
- * An error is raised when unable to find the route.
3565
- */
3566
- findOrFail(routeIdentifier, domain) {
3567
- const routes = this.#routes[domain || "root"] || [];
3568
- return new RouteFinder(routes).findOrFail(routeIdentifier);
3569
- }
3570
- /**
3571
- * Check if a route exists. The identifier can be the
3572
- * route name, controller.method name or the route pattern
3573
- * itself.
3574
- */
3575
- has(routeIdentifier, domain) {
3576
- const routes = this.#routes[domain || "root"] || [];
3577
- return new RouteFinder(routes).has(routeIdentifier);
3578
- }
3579
- toJSON() {
3580
- return this.#routes;
3581
- }
3582
- };
3583
-
3584
- // src/router/matchers.ts
3585
- import Macroable7 from "@poppinss/macroable";
3586
- var RouteMatchers = class extends Macroable7 {
3587
- /**
3588
- * Enforce value to be a number and also casts it to number data
3589
- * type
3590
- */
3591
- number() {
3592
- return { match: /^[0-9]+$/, cast: (value) => Number(value) };
3593
- }
3594
- /**
3595
- * Enforce value to be formatted as uuid
3596
- */
3597
- uuid() {
3598
- return {
3599
- match: /^[0-9a-zA-F]{8}-[0-9a-zA-F]{4}-[0-9a-zA-F]{4}-[0-9a-zA-F]{4}-[0-9a-zA-F]{12}$/,
3600
- cast: (value) => value.toLowerCase()
3601
- };
3602
- }
3603
- /**
3604
- * Enforce value to be formatted as slug
3605
- */
3606
- slug() {
3607
- return { match: /^[^\s-_](?!.*?[-_]{2,})([a-z0-9-\\]{1,})[^\s]*[^-_\s]$/ };
3608
- }
3609
- };
3610
-
3611
- // src/define_middleware.ts
3612
- import { moduleImporter as moduleImporter2 } from "@adonisjs/fold";
3613
- function middlewareReferenceBuilder(name, middleware) {
3614
- const handler = moduleImporter2(middleware, "handle").toHandleMethod();
3615
- return function(...args) {
3616
- return {
3617
- name,
3618
- args: args[0],
3619
- ...handler
3620
- };
3621
- };
3622
- }
3623
- function defineNamedMiddleware(collection) {
3624
- return Object.keys(collection).reduce(
3625
- (result, key) => {
3626
- result[key] = middlewareReferenceBuilder(key, collection[key]);
3627
- return result;
3628
- },
3629
- {}
3630
- );
3631
- }
3632
-
3633
- // src/router/main.ts
3634
- var Router = class extends LookupStore {
3635
- /**
3636
- * Application is needed to resolve string based controller expressions
3637
- */
3638
- #app;
3639
- /**
3640
- * Store with tokenized routes
3641
- */
3642
- #store = new RoutesStore();
3643
- /**
3644
- * Global matchers to test route params against regular expressions.
3645
- */
3646
- #globalMatchers = {};
3647
- /**
3648
- * Middleware store to be shared with the routes
3649
- */
3650
- #middleware = [];
3651
- /**
3652
- * A boolean to tell the router that a group is in
3653
- * open state right now
3654
- */
3655
- #openedGroups = [];
3656
- /**
3657
- * Collection of routes, including route resource and route
3658
- * group. To get a flat list of routes, call `router.toJSON()`
3659
- */
3660
- routes = [];
3661
- /**
3662
- * A flag to know if routes for explicit domains have been registered.
3663
- * The boolean is computed after calling the "commit" method.
3664
- */
3665
- usingDomains = false;
3666
- /**
3667
- * Shortcut methods for commonly used route matchers
3668
- */
3669
- matchers = new RouteMatchers();
3670
- constructor(app, encryption, qsParser) {
3671
- super(encryption, qsParser);
3672
- this.#app = app;
3673
- }
3674
- /**
3675
- * Push a give router entity to the list of routes or the
3676
- * recently opened group.
3677
- */
3678
- #pushToRoutes(entity) {
3679
- const openedGroup = this.#openedGroups[this.#openedGroups.length - 1];
3680
- if (openedGroup) {
3681
- openedGroup.routes.push(entity);
3682
- return;
3683
- }
3684
- this.routes.push(entity);
3685
- }
3686
- /**
3687
- * Parses the route pattern
3688
- */
3689
- parsePattern(pattern, matchers) {
3690
- return parseRoutePattern(pattern, matchers);
3691
- }
3692
- /**
3693
- * Define an array of middleware to use on all the routes.
3694
- * Calling this method multiple times pushes to the
3695
- * existing list of middleware
3696
- */
3697
- use(middleware) {
3698
- middleware.forEach(
3699
- (one) => this.#middleware.push(moduleImporter3(one, "handle").toHandleMethod())
3700
- );
3701
- return this;
3702
- }
3703
- /**
3704
- * Define a collection of named middleware. The defined collection is
3705
- * not registered anywhere, but instead converted in a new collection
3706
- * of functions you can apply on the routes, or router groups.
3707
- */
3708
- named(collection) {
3709
- return defineNamedMiddleware(collection);
3710
- }
3711
- /**
3712
- * Add route for a given pattern and methods
3713
- */
3714
- route(pattern, methods, handler) {
3715
- const route = new Route(this.#app, this.#middleware, {
3716
- pattern,
3717
- methods,
3718
- handler,
3719
- globalMatchers: this.#globalMatchers
3720
- });
3721
- this.#pushToRoutes(route);
3722
- return route;
3723
- }
3724
- /**
3725
- * Define a route that handles all common HTTP methods
3726
- */
3727
- any(pattern, handler) {
3728
- return this.route(
3729
- pattern,
3730
- ["HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"],
3731
- handler
3732
- );
3733
- }
3734
- /**
3735
- * Define `GET` route
3736
- */
3737
- get(pattern, handler) {
3738
- return this.route(pattern, ["GET", "HEAD"], handler);
3739
- }
3740
- /**
3741
- * Define `POST` route
3742
- */
3743
- post(pattern, handler) {
3744
- return this.route(pattern, ["POST"], handler);
3745
- }
3746
- /**
3747
- * Define `PUT` route
3748
- */
3749
- put(pattern, handler) {
3750
- return this.route(pattern, ["PUT"], handler);
3751
- }
3752
- /**
3753
- * Define `PATCH` route
3754
- */
3755
- patch(pattern, handler) {
3756
- return this.route(pattern, ["PATCH"], handler);
3757
- }
3758
- /**
3759
- * Define `DELETE` route
3760
- */
3761
- delete(pattern, handler) {
3762
- return this.route(pattern, ["DELETE"], handler);
3763
- }
3764
- /**
3765
- * Creates a group of routes. A route group can apply transforms
3766
- * to routes in bulk
3767
- */
3768
- group(callback) {
3769
- const group = new RouteGroup([]);
3770
- this.#pushToRoutes(group);
3771
- this.#openedGroups.push(group);
3772
- callback();
3773
- this.#openedGroups.pop();
3774
- return group;
3775
- }
3776
- /**
3777
- * Registers a route resource with conventional set of routes
3778
- */
3779
- resource(resource, controller) {
3780
- const resourceInstance = new RouteResource(this.#app, this.#middleware, {
3781
- resource,
3782
- controller,
3783
- shallow: false,
3784
- globalMatchers: this.#globalMatchers
3785
- });
3786
- this.#pushToRoutes(resourceInstance);
3787
- return resourceInstance;
3788
- }
3789
- /**
3790
- * Register a route resource with shallow nested routes.
3791
- */
3792
- shallowResource(resource, controller) {
3793
- const resourceInstance = new RouteResource(this.#app, this.#middleware, {
3794
- resource,
3795
- controller,
3796
- shallow: true,
3797
- globalMatchers: this.#globalMatchers
3798
- });
3799
- this.#pushToRoutes(resourceInstance);
3800
- return resourceInstance;
3801
- }
3802
- /**
3803
- * Returns a brisk route instance for a given URL pattern
3804
- */
3805
- on(pattern) {
3806
- const briskRoute = new BriskRoute(this.#app, this.#middleware, {
3807
- pattern,
3808
- globalMatchers: this.#globalMatchers
3809
- });
3810
- this.#pushToRoutes(briskRoute);
3811
- return briskRoute;
3812
- }
3813
- /**
3814
- * Define matcher for a given param. The global params are applied
3815
- * on all the routes (unless overridden at the route level).
3816
- */
3817
- where(param, matcher) {
3818
- if (typeof matcher === "string") {
3819
- this.#globalMatchers[param] = { match: new RegExp(matcher) };
3820
- } else if (is3.regExp(matcher)) {
3821
- this.#globalMatchers[param] = { match: matcher };
3822
- } else {
3823
- this.#globalMatchers[param] = matcher;
3824
- }
3825
- return this;
3826
- }
3827
- /**
3828
- * Commit routes to the store. The router is freezed after the
3829
- * commit method is called.
3830
- */
3831
- commit() {
3832
- const routeNamesByDomain = /* @__PURE__ */ new Map();
3833
- toRoutesJSON(this.routes).forEach((route) => {
3834
- if (!routeNamesByDomain.has(route.domain)) {
3835
- routeNamesByDomain.set(route.domain, /* @__PURE__ */ new Set());
3836
- }
3837
- const routeNames = routeNamesByDomain.get(route.domain);
3838
- if (route.name && routeNames.has(route.name)) {
3839
- throw new RuntimeException6(
3840
- `Route with duplicate name found. A route with name "${route.name}" already exists`
3841
- );
3842
- }
3843
- if (route.name) {
3844
- routeNames.add(route.name);
3845
- }
3846
- this.register(route);
3847
- this.#store.add(route);
3848
- });
3849
- routeNamesByDomain.clear();
3850
- this.usingDomains = this.#store.usingDomains;
3851
- this.routes = [];
3852
- this.#globalMatchers = {};
3853
- this.#middleware = [];
3854
- }
3855
- /**
3856
- * Find route for a given URL, method and optionally domain
3857
- */
3858
- match(url, method, hostname) {
3859
- const matchingDomain = this.#store.matchDomain(hostname);
3860
- return matchingDomain.length ? this.#store.match(url, method, {
3861
- tokens: matchingDomain,
3862
- hostname
3863
- }) : this.#store.match(url, method);
3864
- }
3865
- /**
3866
- * Make URL to a pre-registered route
3867
- */
3868
- makeUrl(routeIdentifier, params, options) {
3869
- const normalizedOptions = Object.assign({}, options);
3870
- const builder = normalizedOptions.domain ? this.builderForDomain(normalizedOptions.domain) : this.builder();
3871
- builder.params(params);
3872
- builder.qs(normalizedOptions.qs);
3873
- normalizedOptions.prefixUrl && builder.prefixUrl(normalizedOptions.prefixUrl);
3874
- normalizedOptions.disableRouteLookup && builder.disableRouteLookup();
3875
- return builder.make(routeIdentifier);
3876
- }
3877
- /**
3878
- * Makes a signed URL to a pre-registered route.
3879
- */
3880
- makeSignedUrl(routeIdentifier, params, options) {
3881
- const normalizedOptions = Object.assign({}, options);
3882
- const builder = normalizedOptions.domain ? this.builderForDomain(normalizedOptions.domain) : this.builder();
3883
- builder.params(params);
3884
- builder.qs(normalizedOptions.qs);
3885
- normalizedOptions.prefixUrl && builder.prefixUrl(normalizedOptions.prefixUrl);
3886
- normalizedOptions.disableRouteLookup && builder.disableRouteLookup();
3887
- return builder.makeSigned(routeIdentifier, normalizedOptions);
3888
- }
3889
- };
3890
-
3891
- // src/http_context/main.ts
3892
- import { inspect } from "node:util";
3893
- import Macroable8 from "@poppinss/macroable";
3894
- import { RuntimeException as RuntimeException7 } from "@poppinss/utils";
3895
-
3896
- // src/http_context/local_storage.ts
3897
- import { AsyncLocalStorage } from "node:async_hooks";
3898
- var asyncLocalStorage = {
3899
- /**
3900
- * Check if the async local storage for the HTTP
3901
- * context is enabled or not
3902
- */
3903
- isEnabled: false,
3904
- /**
3905
- * HTTP context storage instance for the current scope
3906
- */
3907
- storage: null,
3908
- /**
3909
- * Create the storage instance. This method must be called only
3910
- * once.
3911
- */
3912
- create() {
3913
- this.isEnabled = true;
3914
- this.storage = new AsyncLocalStorage();
3915
- return this.storage;
3916
- },
3917
- /**
3918
- * Destroy the create storage instance
3919
- */
3920
- destroy() {
3921
- this.isEnabled = false;
3922
- this.storage = null;
3923
- }
3924
- };
3925
-
3926
- // src/http_context/main.ts
3927
- var HttpContext = class extends Macroable8 {
3928
- constructor(request, response, logger, containerResolver) {
3929
- super();
3930
- this.request = request;
3931
- this.response = response;
3932
- this.logger = logger;
3933
- this.containerResolver = containerResolver;
3934
- this.request.ctx = this;
3935
- this.response.ctx = this;
3936
- }
3937
- /**
3938
- * Find if async localstorage is enabled for HTTP requests
3939
- * or not
3940
- */
3941
- static get usingAsyncLocalStorage() {
3942
- return asyncLocalStorage.isEnabled;
3943
- }
3944
- /**
3945
- * Get access to the HTTP context. Available only when
3946
- * "usingAsyncLocalStorage" is true
3947
- */
3948
- static get() {
3949
- if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) {
3950
- return null;
3951
- }
3952
- return asyncLocalStorage.storage.getStore() || null;
3953
- }
3954
- /**
3955
- * Get the HttpContext instance or raise an exception if not
3956
- * available
3957
- */
3958
- static getOrFail() {
3959
- if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) {
3960
- throw new RuntimeException7(
3961
- 'HTTP context is not available. Enable "useAsyncLocalStorage" inside "config/app.ts" file'
3962
- );
3963
- }
3964
- const store = this.get();
3965
- if (!store) {
3966
- throw new RuntimeException7("Http context is not available outside of an HTTP request");
3967
- }
3968
- return store;
3969
- }
3970
- /**
3971
- * Run a method that doesn't have access to HTTP context from
3972
- * the async local storage.
3973
- */
3974
- static runOutsideContext(callback, ...args) {
3975
- if (!asyncLocalStorage.storage) {
3976
- return callback(...args);
3977
- }
3978
- return asyncLocalStorage.storage.exit(callback, ...args);
3979
- }
3980
- /**
3981
- * Reference to the current route. Not available inside
3982
- * server middleware
3983
- */
3984
- route;
3985
- /**
3986
- * A unique key for the current route
3987
- */
3988
- routeKey;
3989
- /**
3990
- * Route params
3991
- */
3992
- params = {};
3993
- /**
3994
- * Route subdomains
3995
- */
3996
- subdomains = {};
3997
- /**
3998
- * A helper to see top level properties on the context object
3999
- */
4000
- /* c8 ignore next 3 */
4001
- inspect() {
4002
- return inspect(this, false, 1, true);
4003
- }
4004
- };
4005
-
4006
- // src/server/main.ts
4007
- import onFinished2 from "on-finished";
4008
- import Middleware2 from "@poppinss/middleware";
4009
- import { moduleCaller as moduleCaller2, moduleImporter as moduleImporter4 } from "@adonisjs/fold";
4010
-
4011
- // src/qs.ts
4012
- import { parse as parse3, stringify } from "qs";
4013
- var Qs = class {
4014
- #config;
4015
- constructor(config) {
4016
- this.#config = config;
4017
- }
4018
- parse(value) {
4019
- return parse3(value, this.#config.parse);
4020
- }
4021
- stringify(value) {
4022
- return stringify(value, this.#config.stringify);
4023
- }
4024
- };
4025
-
4026
- // src/server/factories/final_handler.ts
4027
- function finalHandler(router, resolver, ctx, errorResponder) {
4028
- return function() {
4029
- const url = ctx.request.url();
4030
- const method = ctx.request.method();
4031
- const hostname = router.usingDomains ? ctx.request.hostname() : void 0;
4032
- const route = router.match(url, method, hostname);
4033
- if (route) {
4034
- ctx.params = route.params;
4035
- ctx.subdomains = route.subdomains;
4036
- ctx.route = route.route;
4037
- ctx.routeKey = route.routeKey;
4038
- return route.route.execute(route.route, resolver, ctx, errorResponder);
4039
- }
4040
- return Promise.reject(new E_ROUTE_NOT_FOUND([method, url]));
4041
- };
4042
- }
4043
-
4044
- // src/server/factories/write_response.ts
4045
- function writeResponse(ctx) {
4046
- return function() {
4047
- try {
4048
- ctx.response.finish();
4049
- } catch (error) {
4050
- ctx.logger.fatal({ err: error }, "Response serialization failed");
4051
- ctx.response.internalServerError(error.message);
4052
- ctx.response.finish();
4053
- }
4054
- };
4055
- }
4056
-
4057
- // src/server/factories/middleware_handler.ts
4058
- function middlewareHandler(resolver, ctx) {
4059
- return function(fn, next) {
4060
- return fn.handle(resolver, ctx, next);
4061
- };
4062
- }
4063
-
4064
- // src/server/main.ts
4065
- var Server = class {
4066
- /**
4067
- * The default error handler to use
4068
- */
4069
- #defaultErrorHandler = {
4070
- report() {
4071
- },
4072
- handle(error, ctx) {
4073
- ctx.response.status(error.status || 500).send(error.message || "Internal server error");
4074
- }
4075
- };
4076
- /**
4077
- * Logger instance, a child logger is added
4078
- * to the context to have request specific
4079
- * logging capabilities.
4080
- */
4081
- #logger;
4082
- /**
4083
- * Registered error handler (if any)
4084
- */
4085
- #errorHandler;
4086
- /**
4087
- * Resolved error handler is an instance of the lazily imported error
4088
- * handler class.
4089
- */
4090
- #resolvedErrorHandler = this.#defaultErrorHandler;
4091
- /**
4092
- * Emitter is required to notify when a request finishes
4093
- */
4094
- #emitter;
4095
- /**
4096
- * The application instance to be shared with the router
4097
- */
4098
- #app;
4099
- /**
4100
- * The encryption instance to be shared with the router
4101
- */
4102
- #encryption;
4103
- /**
4104
- * Server config
4105
- */
4106
- #config;
4107
- /**
4108
- * Query string parser used by the server
4109
- */
4110
- #qsParser;
4111
- /**
4112
- * Server middleware stack runs on every incoming HTTP request
4113
- */
4114
- #serverMiddlewareStack;
4115
- /**
4116
- * Reference to the router used by the server
4117
- */
4118
- #router;
4119
- /**
4120
- * Reference to the underlying Node HTTP server in use
4121
- */
4122
- #nodeHttpServer;
4123
- /**
4124
- * Middleware store to be shared with the routes
4125
- */
4126
- #middleware = [];
4127
- /**
4128
- * The request error response is attached to the middleware
4129
- * pipeline to intercept errors and invoke the user
4130
- * registered error handler.
4131
- *
4132
- * We share this with the route middleware pipeline as well,
4133
- * so that it does not throw any exceptions
4134
- */
4135
- #requestErrorResponder = (error, ctx) => {
4136
- this.#resolvedErrorHandler.report(error, ctx);
4137
- return this.#resolvedErrorHandler.handle(error, ctx);
4138
- };
4139
- /**
4140
- * Know if async local storage is enabled or not.
4141
- */
4142
- get usingAsyncLocalStorage() {
4143
- return asyncLocalStorage.isEnabled;
4144
- }
4145
- constructor(app, encryption, emitter, logger, config) {
4146
- this.#app = app;
4147
- this.#emitter = emitter;
4148
- this.#config = config;
4149
- this.#logger = logger;
4150
- this.#encryption = encryption;
4151
- this.#qsParser = new Qs(this.#config.qs);
4152
- this.#router = new Router(this.#app, this.#encryption, this.#qsParser);
4153
- this.#createAsyncLocalStore();
4154
- debug_default("server config: %O", this.#config);
4155
- }
4156
- /**
4157
- * Create async local storage store when enabled
4158
- */
4159
- #createAsyncLocalStore() {
4160
- if (this.#config.useAsyncLocalStorage) {
4161
- debug_default("creating ALS store for HTTP context");
4162
- asyncLocalStorage.create();
4163
- } else {
4164
- asyncLocalStorage.destroy();
4165
- }
4166
- }
4167
- /**
4168
- * Creates an instance of the server middleware stack
4169
- */
4170
- #createServerMiddlewareStack() {
4171
- this.#serverMiddlewareStack = new Middleware2();
4172
- this.#middleware.forEach((middleware) => this.#serverMiddlewareStack.add(middleware));
4173
- this.#serverMiddlewareStack.freeze();
4174
- this.#middleware = [];
4175
- }
4176
- /**
4177
- * Handles the HTTP request
4178
- */
4179
- #handleRequest(ctx, resolver) {
4180
- return this.#serverMiddlewareStack.runner().errorHandler((error) => this.#requestErrorResponder(error, ctx)).finalHandler(finalHandler(this.#router, resolver, ctx, this.#requestErrorResponder)).run(middlewareHandler(resolver, ctx)).catch((error) => {
4181
- ctx.logger.fatal({ err: error }, "Exception raised by error handler");
4182
- return this.#defaultErrorHandler.handle(error, ctx);
4183
- }).finally(writeResponse(ctx));
4184
- }
4185
- /**
4186
- * Creates a pipeline of middleware.
4187
- */
4188
- pipeline(middleware) {
4189
- const middlewareStack = new Middleware2();
4190
- middleware.forEach((one) => {
4191
- middlewareStack.add(moduleCaller2(one, "handle").toHandleMethod());
4192
- });
4193
- middlewareStack.freeze();
4194
- const stackRunner = middlewareStack.runner();
4195
- return {
4196
- finalHandler(handler) {
4197
- stackRunner.finalHandler(handler);
4198
- return this;
4199
- },
4200
- errorHandler(handler) {
4201
- stackRunner.errorHandler(handler);
4202
- return this;
4203
- },
4204
- run(ctx) {
4205
- return stackRunner.run((handler, next) => {
4206
- return handler.handle(ctx.containerResolver, ctx, next);
4207
- });
4208
- }
4209
- };
4210
- }
4211
- /**
4212
- * Define an array of middleware to use on all the incoming HTTP request.
4213
- * Calling this method multiple times pushes to the existing list
4214
- * of middleware
4215
- */
4216
- use(middleware) {
4217
- middleware.forEach(
4218
- (one) => this.#middleware.push(moduleImporter4(one, "handle").toHandleMethod())
4219
- );
4220
- return this;
4221
- }
4222
- /**
4223
- * Register a custom error handler for HTTP requests.
4224
- * All errors will be reported to this method
4225
- */
4226
- errorHandler(handler) {
4227
- this.#errorHandler = handler;
4228
- return this;
4229
- }
4230
- /**
4231
- * Boot the server. Calling this method performs the following actions.
4232
- *
4233
- * - Register routes with the store.
4234
- * - Resolve and construct the error handler.
4235
- */
4236
- async boot() {
4237
- debug_default("booting HTTP server");
4238
- this.#createServerMiddlewareStack();
4239
- this.#router.commit();
4240
- if (this.#errorHandler) {
4241
- if (debug_default.enabled) {
4242
- debug_default('using custom error handler "%s"', this.#errorHandler);
4243
- }
4244
- const moduleExports = await this.#errorHandler();
4245
- this.#resolvedErrorHandler = await this.#app.container.make(moduleExports.default);
4246
- }
4247
- }
4248
- /**
4249
- * Set the HTTP server instance used to listen for requests.
4250
- */
4251
- setNodeServer(server) {
4252
- this.#nodeHttpServer = server;
4253
- }
4254
- /**
4255
- * Returns reference to the underlying HTTP server
4256
- * in use
4257
- */
4258
- getNodeServer() {
4259
- return this.#nodeHttpServer;
4260
- }
4261
- /**
4262
- * Returns reference to the router instance used
4263
- * by the server.
4264
- */
4265
- getRouter() {
4266
- return this.#router;
4267
- }
4268
- /**
4269
- * Creates an instance of the [[Request]] class
4270
- */
4271
- createRequest(req, res) {
4272
- return new Request(req, res, this.#encryption, this.#config, this.#qsParser);
4273
- }
4274
- /**
4275
- * Creates an instance of the [[Response]] class
4276
- */
4277
- createResponse(req, res) {
4278
- return new Response(req, res, this.#encryption, this.#config, this.#router, this.#qsParser);
4279
- }
4280
- /**
4281
- * Creates an instance of the [[HttpContext]] class
4282
- */
4283
- createHttpContext(request, response, resolver) {
4284
- return new HttpContext(
4285
- request,
4286
- response,
4287
- this.#logger.child({ request_id: request.id() }),
4288
- resolver
4289
- );
4290
- }
4291
- /**
4292
- * Handle request
4293
- */
4294
- handle(req, res) {
4295
- const hasRequestListener = this.#emitter.hasListeners("http:request_finished");
4296
- const startTime = hasRequestListener ? process.hrtime() : null;
4297
- const resolver = this.#app.container.createResolver();
4298
- const ctx = this.createHttpContext(
4299
- this.createRequest(req, res),
4300
- this.createResponse(req, res),
4301
- resolver
4302
- );
4303
- if (startTime) {
4304
- onFinished2(res, () => {
4305
- this.#emitter.emit("http:request_finished", {
4306
- ctx,
4307
- duration: process.hrtime(startTime)
4308
- });
4309
- });
4310
- }
4311
- if (this.usingAsyncLocalStorage) {
4312
- return asyncLocalStorage.storage.run(ctx, () => this.#handleRequest(ctx, resolver));
4313
- }
4314
- return this.#handleRequest(ctx, resolver);
4315
- }
4316
- };
4317
-
4318
- // src/define_config.ts
4319
- import proxyAddr from "proxy-addr";
4320
- import string3 from "@poppinss/utils/string";
4321
- function defineConfig(config) {
4322
- const { trustProxy: trustProxy2, ...rest } = config;
4323
- const normalizedConfig = {
4324
- allowMethodSpoofing: false,
4325
- trustProxy: proxyAddr.compile("loopback"),
4326
- subdomainOffset: 2,
4327
- generateRequestId: false,
4328
- useAsyncLocalStorage: false,
4329
- etag: false,
4330
- jsonpCallbackName: "callback",
4331
- cookie: {
4332
- maxAge: "2h",
4333
- path: "/",
4334
- httpOnly: true,
4335
- secure: false,
4336
- sameSite: false
4337
- },
4338
- qs: {
4339
- parse: {
4340
- depth: 5,
4341
- parameterLimit: 1e3,
4342
- allowSparse: false,
4343
- arrayLimit: 20,
4344
- comma: true
4345
- },
4346
- stringify: {
4347
- encode: true,
4348
- encodeValuesOnly: false,
4349
- arrayFormat: "indices",
4350
- skipNulls: false
4351
- }
4352
- },
4353
- ...rest
4354
- };
4355
- if (normalizedConfig.cookie.maxAge) {
4356
- normalizedConfig.cookie.maxAge = string3.seconds.parse(normalizedConfig.cookie.maxAge);
4357
- }
4358
- if (typeof trustProxy2 === "boolean") {
4359
- const tpValue = trustProxy2;
4360
- normalizedConfig.trustProxy = (_, __) => tpValue;
4361
- } else if (typeof trustProxy2 === "string") {
4362
- const tpValue = trustProxy2;
4363
- normalizedConfig.trustProxy = proxyAddr.compile(tpValue);
4364
- }
4365
- return normalizedConfig;
4366
- }
4367
-
4368
- export {
4369
- Route,
4370
- BriskRoute,
4371
- RouteResource,
4372
- RouteGroup,
4373
- parseRange,
4374
- CookieClient,
4375
- Request,
4376
- Redirect,
4377
- E_ROUTE_NOT_FOUND,
4378
- E_CANNOT_LOOKUP_ROUTE,
4379
- E_HTTP_EXCEPTION,
4380
- E_HTTP_REQUEST_ABORTED,
4381
- exceptions_exports,
4382
- Response,
4383
- Qs,
4384
- Router,
4385
- HttpContext,
4386
- Server,
4387
- defineConfig
4388
- };