@deepkit/http 1.0.19 → 1.1.0

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 (85) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/cjs/index.d.ts +2 -0
  3. package/dist/cjs/index.js +2 -0
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/src/decorator.js +11 -7
  6. package/dist/cjs/src/decorator.js.map +1 -1
  7. package/dist/cjs/src/filter.js +1 -1
  8. package/dist/cjs/src/filter.js.map +1 -1
  9. package/dist/cjs/src/http.d.ts +3 -0
  10. package/dist/cjs/src/http.js +90 -61
  11. package/dist/cjs/src/http.js.map +1 -1
  12. package/dist/cjs/src/logger.js +0 -7
  13. package/dist/cjs/src/logger.js.map +1 -1
  14. package/dist/cjs/src/middleware.d.ts +2 -2
  15. package/dist/cjs/src/middleware.js +2 -2
  16. package/dist/cjs/src/mime.d.ts +19 -0
  17. package/dist/cjs/src/mime.js +147 -0
  18. package/dist/cjs/src/mime.js.map +1 -0
  19. package/dist/cjs/src/model.d.ts +7 -0
  20. package/dist/cjs/src/model.js +16 -7
  21. package/dist/cjs/src/model.js.map +1 -1
  22. package/dist/cjs/src/module.js +9 -5
  23. package/dist/cjs/src/module.js.map +1 -1
  24. package/dist/cjs/src/query-string.d.ts +6 -0
  25. package/dist/cjs/src/query-string.js +229 -0
  26. package/dist/cjs/src/query-string.js.map +1 -0
  27. package/dist/cjs/src/request-parser.js +12 -10
  28. package/dist/cjs/src/request-parser.js.map +1 -1
  29. package/dist/cjs/src/router.js +14 -15
  30. package/dist/cjs/src/router.js.map +1 -1
  31. package/dist/cjs/src/static-serving.d.ts +6 -0
  32. package/dist/cjs/src/static-serving.js +232 -28
  33. package/dist/cjs/src/static-serving.js.map +1 -1
  34. package/dist/cjs/src/utils.js +1 -1
  35. package/dist/cjs/src/utils.js.map +1 -1
  36. package/dist/esm/index.d.ts +2 -0
  37. package/dist/esm/index.js +2 -0
  38. package/dist/esm/index.js.map +1 -1
  39. package/dist/esm/src/decorator.js +11 -7
  40. package/dist/esm/src/decorator.js.map +1 -1
  41. package/dist/esm/src/filter.js +1 -1
  42. package/dist/esm/src/filter.js.map +1 -1
  43. package/dist/esm/src/http.d.ts +3 -0
  44. package/dist/esm/src/http.js +55 -60
  45. package/dist/esm/src/http.js.map +1 -1
  46. package/dist/esm/src/logger.js +0 -7
  47. package/dist/esm/src/logger.js.map +1 -1
  48. package/dist/esm/src/middleware.d.ts +2 -2
  49. package/dist/esm/src/middleware.js +2 -2
  50. package/dist/esm/src/mime.d.ts +19 -0
  51. package/dist/esm/src/mime.js +142 -0
  52. package/dist/esm/src/mime.js.map +1 -0
  53. package/dist/esm/src/model.d.ts +7 -0
  54. package/dist/esm/src/model.js +16 -7
  55. package/dist/esm/src/model.js.map +1 -1
  56. package/dist/esm/src/module.js +9 -5
  57. package/dist/esm/src/module.js.map +1 -1
  58. package/dist/esm/src/query-string.d.ts +6 -0
  59. package/dist/esm/src/query-string.js +226 -0
  60. package/dist/esm/src/query-string.js.map +1 -0
  61. package/dist/esm/src/request-parser.js +12 -10
  62. package/dist/esm/src/request-parser.js.map +1 -1
  63. package/dist/esm/src/router.js +14 -12
  64. package/dist/esm/src/router.js.map +1 -1
  65. package/dist/esm/src/static-serving.d.ts +6 -0
  66. package/dist/esm/src/static-serving.js +234 -27
  67. package/dist/esm/src/static-serving.js.map +1 -1
  68. package/dist/esm/src/utils.js +1 -1
  69. package/dist/esm/src/utils.js.map +1 -1
  70. package/index.ts +2 -0
  71. package/package.json +22 -25
  72. package/src/http.ts +40 -6
  73. package/src/middleware.ts +2 -2
  74. package/src/mime.ts +141 -0
  75. package/src/model.ts +10 -2
  76. package/src/module.ts +4 -2
  77. package/src/query-string.ts +228 -0
  78. package/src/request-parser.ts +6 -4
  79. package/src/router.ts +3 -3
  80. package/src/static-serving.ts +221 -8
  81. package/tsconfig.json +3 -17
  82. package/tsconfig.spec.json +4 -1
  83. package/LICENSE +0 -21
  84. package/dist/cjs/tsconfig.tsbuildinfo +0 -1
  85. package/dist/esm/tsconfig.esm.tsbuildinfo +0 -1
package/src/mime.ts ADDED
@@ -0,0 +1,141 @@
1
+ /*
2
+ * Deepkit Framework
3
+ * Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the MIT License.
7
+ *
8
+ * You should have received a copy of the MIT License along with this program.
9
+ */
10
+ import { extname } from 'path';
11
+
12
+ /**
13
+ * File extension to MIME type map of common web types.
14
+ * Add more types at runtime by setting `mimeTypes[extension] = type`.
15
+ */
16
+ export const mimeTypes: { [extension: string]: string } = {
17
+ // text
18
+ html: 'text/html',
19
+ htm: 'text/html',
20
+ css: 'text/css',
21
+ js: 'text/javascript',
22
+ mjs: 'text/javascript',
23
+ cjs: 'application/node',
24
+ txt: 'text/plain',
25
+ text: 'text/plain',
26
+ csv: 'text/csv',
27
+ tsv: 'text/tab-separated-values',
28
+ md: 'text/markdown',
29
+ markdown: 'text/markdown',
30
+ yaml: 'text/yaml',
31
+ yml: 'text/yaml',
32
+ ics: 'text/calendar',
33
+ vtt: 'text/vtt',
34
+ appcache: 'text/cache-manifest',
35
+ // application
36
+ json: 'application/json',
37
+ map: 'application/json',
38
+ jsonld: 'application/ld+json',
39
+ webmanifest: 'application/manifest+json',
40
+ xml: 'application/xml',
41
+ xsl: 'application/xml',
42
+ rtf: 'application/rtf',
43
+ wasm: 'application/wasm',
44
+ pdf: 'application/pdf',
45
+ zip: 'application/zip',
46
+ gz: 'application/gzip',
47
+ tar: 'application/x-tar',
48
+ bz2: 'application/x-bzip2',
49
+ '7z': 'application/x-7z-compressed',
50
+ rar: 'application/vnd.rar',
51
+ xz: 'application/x-xz',
52
+ bin: 'application/octet-stream',
53
+ epub: 'application/epub+zip',
54
+ doc: 'application/msword',
55
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
56
+ xls: 'application/vnd.ms-excel',
57
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
58
+ ppt: 'application/vnd.ms-powerpoint',
59
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
60
+ odt: 'application/vnd.oasis.opendocument.text',
61
+ ods: 'application/vnd.oasis.opendocument.spreadsheet',
62
+ odp: 'application/vnd.oasis.opendocument.presentation',
63
+ m3u8: 'application/vnd.apple.mpegurl',
64
+ mpd: 'application/dash+xml',
65
+ // images
66
+ png: 'image/png',
67
+ apng: 'image/apng',
68
+ jpg: 'image/jpeg',
69
+ jpeg: 'image/jpeg',
70
+ jpe: 'image/jpeg',
71
+ gif: 'image/gif',
72
+ webp: 'image/webp',
73
+ avif: 'image/avif',
74
+ svg: 'image/svg+xml',
75
+ svgz: 'image/svg+xml',
76
+ ico: 'image/vnd.microsoft.icon',
77
+ bmp: 'image/bmp',
78
+ tif: 'image/tiff',
79
+ tiff: 'image/tiff',
80
+ heic: 'image/heic',
81
+ heif: 'image/heif',
82
+ jxl: 'image/jxl',
83
+ psd: 'image/vnd.adobe.photoshop',
84
+ // fonts
85
+ woff: 'font/woff',
86
+ woff2: 'font/woff2',
87
+ ttf: 'font/ttf',
88
+ otf: 'font/otf',
89
+ eot: 'application/vnd.ms-fontobject',
90
+ // audio
91
+ mp3: 'audio/mpeg',
92
+ m4a: 'audio/mp4',
93
+ aac: 'audio/aac',
94
+ oga: 'audio/ogg',
95
+ ogg: 'audio/ogg',
96
+ opus: 'audio/ogg',
97
+ wav: 'audio/wav',
98
+ flac: 'audio/x-flac',
99
+ // video
100
+ mp4: 'video/mp4',
101
+ m4v: 'video/x-m4v',
102
+ webm: 'video/webm',
103
+ ogv: 'video/ogg',
104
+ mov: 'video/quicktime',
105
+ avi: 'video/x-msvideo',
106
+ mkv: 'video/x-matroska',
107
+ mpeg: 'video/mpeg',
108
+ mpg: 'video/mpeg',
109
+ '3gp': 'video/3gpp',
110
+ ts: 'video/mp2t',
111
+ // 3d models
112
+ glb: 'model/gltf-binary',
113
+ gltf: 'model/gltf+json',
114
+ obj: 'model/obj',
115
+ stl: 'model/stl',
116
+ usdz: 'model/vnd.usdz+zip',
117
+ };
118
+
119
+ /**
120
+ * Returns the MIME type for a file path, file name, or extension (with or without leading dot).
121
+ * Returns undefined for unknown extensions.
122
+ *
123
+ * `getMimeType('/assets/logo.svg')` → `image/svg+xml`
124
+ */
125
+ export function getMimeType(path: string): string | undefined {
126
+ const extension = extname('x.' + path)
127
+ .slice(1)
128
+ .toLowerCase();
129
+ return Object.prototype.hasOwnProperty.call(mimeTypes, extension) ? mimeTypes[extension] : undefined;
130
+ }
131
+
132
+ /**
133
+ * Returns the value for a Content-Type header, including `charset=utf-8` for text types.
134
+ * Returns undefined for unknown extensions.
135
+ */
136
+ export function getContentType(path: string): string | undefined {
137
+ const type = getMimeType(path);
138
+ if (!type) return;
139
+ const isText = type.startsWith('text/') || type === 'application/json' || type === 'application/manifest+json';
140
+ return isText ? type + '; charset=utf-8' : type;
141
+ }
package/src/model.ts CHANGED
@@ -312,13 +312,21 @@ export class RequestBuilder {
312
312
  }, this.contentBuffer);
313
313
  }
314
314
 
315
+ /**
316
+ * Replaces all headers. Names are lowercased like Node does for incoming requests.
317
+ */
315
318
  headers(headers: { [name: string]: string }): this {
316
- this._headers = headers;
319
+ this._headers = {};
320
+ for (const [name, value] of Object.entries(headers)) this.header(name, value);
317
321
  return this;
318
322
  }
319
323
 
324
+ /**
325
+ * Sets a header. The name is lowercased like Node does for incoming requests,
326
+ * so `header('Authorization', ...)` is found by `authorization: HttpHeader<string>`.
327
+ */
320
328
  header(name: string, value: string | number): this {
321
- this._headers[name] = String(value);
329
+ this._headers[name.toLowerCase()] = String(value);
322
330
  return this;
323
331
  }
324
332
 
package/src/module.ts CHANGED
@@ -32,8 +32,9 @@ export class HttpModule extends createModuleClass({
32
32
  HttpResultFormatter,
33
33
  HttpRouterRegistry,
34
34
  HttpRouterFilterResolver,
35
- { provide: HttpResponse, scope: 'http' },
36
- { provide: HttpRequest, scope: 'http' },
35
+ { provide: InjectorContext, useValue: undefined, scope: 'http' },
36
+ { provide: HttpResponse, useValue: undefined, scope: 'http' },
37
+ { provide: HttpRequest, useValue: undefined, scope: 'http' },
37
38
  { provide: RouteConfig, useValue: undefined, scope: 'http' },
38
39
  { provide: Logger, useValue: new Logger([new ConsoleTransport()]) },
39
40
  ],
@@ -49,6 +50,7 @@ export class HttpModule extends createModuleClass({
49
50
  HttpKernel,
50
51
  HttpResultFormatter,
51
52
  HttpRouterFilterResolver,
53
+ InjectorContext,
52
54
  HttpResponse,
53
55
  HttpRequest,
54
56
  HttpControllers,
@@ -0,0 +1,228 @@
1
+ /*
2
+ * Deepkit Framework
3
+ * Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the MIT License.
7
+ *
8
+ * You should have received a copy of the MIT License along with this program.
9
+ */
10
+
11
+ /**
12
+ * Query string parser compatible with the default behavior of `qs.parse`.
13
+ *
14
+ * Supports nested objects (`a[b]=1`), arrays (`a[]=1`, `a[0]=1`) and duplicate keys (`a=1&a=2` becomes an array).
15
+ *
16
+ * Limits:
17
+ * - at most 1000 parameters are parsed, the rest is ignored
18
+ * - at most 5 levels of nesting, the remainder is used as literal key (`a[b][c][d][e][f][g]` → `a.b.c.d.e.f['[g]']`)
19
+ * - array indices above 20 create object keys instead of sparse arrays (`a[100]=1` → `{a: {100: '1'}}`)
20
+ *
21
+ * Keys that exist on Object.prototype (`__proto__`, `constructor`, `toString`, `hasOwnProperty`, ...) are dropped.
22
+ */
23
+ const parameterLimit = 1000;
24
+ const depthLimit = 5;
25
+ const arrayLimit = 20;
26
+
27
+ const has = Object.prototype.hasOwnProperty;
28
+ const isArray = Array.isArray;
29
+
30
+ function decode(str: string): string {
31
+ if (str.indexOf('+') !== -1) str = str.replace(/\+/g, ' ');
32
+ if (str.indexOf('%') === -1) return str;
33
+ try {
34
+ return decodeURIComponent(str);
35
+ } catch {
36
+ return str;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Query strings without brackets, the common case: `a=1&b=2&a=3` → `{a: ['1', '3'], b: '2'}`.
42
+ * Same result as the general parser, without its nesting and compaction steps.
43
+ */
44
+ function parseFlat(str: string): Record<string, any> {
45
+ const obj: Record<string, any> = {};
46
+ for (const part of str.split('&', parameterLimit)) {
47
+ const pos = part.indexOf('=');
48
+ const key = decode(pos === -1 ? part : part.slice(0, pos));
49
+ if (!key || has.call(Object.prototype, key)) continue;
50
+ const val = pos === -1 ? '' : decode(part.slice(pos + 1));
51
+ obj[key] = has.call(obj, key) ? ([] as any[]).concat(obj[key], val) : val;
52
+ }
53
+ return obj;
54
+ }
55
+
56
+ const nesting = /[[\]]|%5[bd]/i;
57
+
58
+ function parseValues(str: string): Record<string, any> {
59
+ const obj: Record<string, any> = Object.create(null);
60
+ const parts = str.replace(/%5B/gi, '[').replace(/%5D/gi, ']').split('&', parameterLimit);
61
+
62
+ for (const part of parts) {
63
+ const bracketEqualsPos = part.indexOf(']=');
64
+ const pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
65
+
66
+ const key = decode(pos === -1 ? part : part.slice(0, pos));
67
+ const val = pos === -1 ? '' : decode(part.slice(pos + 1));
68
+
69
+ obj[key] = has.call(obj, key) ? ([] as any[]).concat(obj[key], val) : val;
70
+ }
71
+
72
+ return obj;
73
+ }
74
+
75
+ function parseObject(chain: string[], val: any): any {
76
+ let leaf = val;
77
+
78
+ for (let i = chain.length - 1; i >= 0; --i) {
79
+ let obj: any;
80
+ const root = chain[i];
81
+
82
+ if (root === '[]') {
83
+ obj = ([] as any[]).concat(leaf);
84
+ } else {
85
+ obj = {};
86
+ const cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
87
+ const index = parseInt(cleanRoot, 10);
88
+ if (
89
+ !isNaN(index) &&
90
+ root !== cleanRoot &&
91
+ String(index) === cleanRoot &&
92
+ index >= 0 &&
93
+ index <= arrayLimit
94
+ ) {
95
+ obj = [];
96
+ obj[index] = leaf;
97
+ } else if (cleanRoot !== '__proto__') {
98
+ obj[cleanRoot] = leaf;
99
+ }
100
+ }
101
+
102
+ leaf = obj;
103
+ }
104
+
105
+ return leaf;
106
+ }
107
+
108
+ function parseKeys(key: string, val: any): any {
109
+ if (!key) return;
110
+
111
+ const brackets = /(\[[^[\]]*])/;
112
+ const child = /(\[[^[\]]*])/g;
113
+
114
+ let segment = brackets.exec(key);
115
+ const parent = segment ? key.slice(0, segment.index) : key;
116
+
117
+ const keys: string[] = [];
118
+ if (parent) {
119
+ if (has.call(Object.prototype, parent)) return;
120
+ keys.push(parent);
121
+ }
122
+
123
+ let i = 0;
124
+ while ((segment = child.exec(key)) !== null && i < depthLimit) {
125
+ i += 1;
126
+ if (has.call(Object.prototype, segment[1].slice(1, -1))) return;
127
+ keys.push(segment[1]);
128
+ }
129
+
130
+ // depth limit reached, the remainder is used as literal key
131
+ if (segment) keys.push('[' + key.slice(segment.index) + ']');
132
+
133
+ return parseObject(keys, val);
134
+ }
135
+
136
+ function arrayToObject(source: any[]): Record<string, any> {
137
+ const obj: Record<string, any> = {};
138
+ for (let i = 0; i < source.length; ++i) {
139
+ if (source[i] !== undefined) obj[i] = source[i];
140
+ }
141
+ return obj;
142
+ }
143
+
144
+ function merge(target: any, source: any): any {
145
+ if (!source) return target;
146
+
147
+ if (typeof source !== 'object') {
148
+ if (isArray(target)) {
149
+ target.push(source);
150
+ } else if (target && typeof target === 'object') {
151
+ if (!has.call(Object.prototype, source)) target[source] = true;
152
+ } else {
153
+ return [target, source];
154
+ }
155
+ return target;
156
+ }
157
+
158
+ if (!target || typeof target !== 'object') {
159
+ return [target].concat(source);
160
+ }
161
+
162
+ if (isArray(target) && isArray(source)) {
163
+ source.forEach((item, i) => {
164
+ if (has.call(target, i)) {
165
+ const targetItem = target[i];
166
+ if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
167
+ target[i] = merge(targetItem, item);
168
+ } else {
169
+ target.push(item);
170
+ }
171
+ } else {
172
+ target[i] = item;
173
+ }
174
+ });
175
+ return target;
176
+ }
177
+
178
+ const mergeTarget = isArray(target) && !isArray(source) ? arrayToObject(target) : target;
179
+ for (const key of Object.keys(source)) {
180
+ mergeTarget[key] = has.call(mergeTarget, key) ? merge(mergeTarget[key], source[key]) : source[key];
181
+ }
182
+ return mergeTarget;
183
+ }
184
+
185
+ /**
186
+ * Removes holes from (sparse) arrays, e.g. `a[1]=x` results in `['x']`, not `[undefined, 'x']`.
187
+ */
188
+ function compact(value: Record<string, any>): Record<string, any> {
189
+ const queue: { obj: any; prop: string }[] = [{ obj: { o: value }, prop: 'o' }];
190
+ const refs: any[] = [];
191
+
192
+ for (let i = 0; i < queue.length; ++i) {
193
+ const obj = queue[i].obj[queue[i].prop];
194
+ for (const key of Object.keys(obj)) {
195
+ const val = obj[key];
196
+ if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
197
+ queue.push({ obj, prop: key });
198
+ refs.push(val);
199
+ }
200
+ }
201
+ }
202
+
203
+ while (queue.length > 1) {
204
+ const item = queue.pop()!;
205
+ const obj = item.obj[item.prop];
206
+ if (isArray(obj)) item.obj[item.prop] = obj.filter(v => v !== undefined);
207
+ }
208
+
209
+ return value;
210
+ }
211
+
212
+ /**
213
+ * Parses a query string (without leading `?`) into an object.
214
+ *
215
+ * `a=1&b[c]=2&d[]=3&d[]=4` → `{a: '1', b: {c: '2'}, d: ['3', '4']}`
216
+ */
217
+ export function parseQueryString(str: string): Record<string, any> {
218
+ if (!str) return {};
219
+ if (!nesting.test(str)) return parseFlat(str);
220
+
221
+ const values = parseValues(str);
222
+ let obj: Record<string, any> = {};
223
+ for (const key of Object.keys(values)) {
224
+ obj = merge(obj, parseKeys(key, values[key]));
225
+ }
226
+
227
+ return compact(obj);
228
+ }
@@ -19,7 +19,7 @@ import {
19
19
  } from '@deepkit/type';
20
20
  import { BodyValidationError, createRequestWithCachedBody, getRegExp, HttpRequest, ValidatedBody } from './model.js';
21
21
  import { getRouteActionLabel, RouteConfig, UploadedFile, UploadedFileSymbol } from './router.js';
22
- import qs from 'qs';
22
+ import { parseQueryString } from './query-string.js';
23
23
  import formidable, { Fields, Files, Options } from 'formidable';
24
24
  import { HttpParserOptions } from './module.config.js';
25
25
  import type IncomingForm from 'formidable/Formidable.js';
@@ -231,10 +231,10 @@ export function buildRequestParser(parseOptions: HttpParserOptions, parameters:
231
231
  routeConfig
232
232
  });
233
233
  compiler.context.set('ValidationError', ValidationError);
234
- compiler.context.set('qs', qs);
234
+ compiler.context.set('parseQueryString', parseQueryString);
235
235
 
236
236
  let needsQueryString = !!params.find(v => v.query || v.queries || v.requestParser);
237
- const query = needsQueryString ? '_qPosition === -1 ? {} : qs.parse(_url.substr(_qPosition + 1))' : '{}';
237
+ const query = needsQueryString ? '_qPosition === -1 ? {} : parseQueryString(_url.substr(_qPosition + 1))' : '{}';
238
238
 
239
239
  const regexVar = compiler.reserveVariable('regex', new RegExp('^' + pathRegex + '$'));
240
240
 
@@ -329,7 +329,9 @@ export function getRequestParserCodeForParameters(
329
329
 
330
330
  const queryPath = parameter.typePath === undefined && !parameter.queries ? parameter.parameter.name : parameter.typePath;
331
331
  const accessor = queryPath ? `['` + (queryPath.replace(/\./g, `']['`)) + `']` : '';
332
- const queryAccessor = parameter.header ? `_headers${accessor}` : queryPath ? `_query${accessor}` : '_query';
332
+ // header names are case-insensitive, Node lowercases them in request.headers
333
+ const headerAccessor = queryPath ? `_headers[${JSON.stringify(queryPath.toLowerCase())}]` : '_headers';
334
+ const queryAccessor = parameter.header ? headerAccessor : queryPath ? `_query${accessor}` : '_query';
333
335
 
334
336
  if (isOptional(parameter.parameter.parameter) || hasDefaultValue(parameter.parameter.parameter)) {
335
337
  setParameters.push(`parameters.${parameter.parameter.name} = ${queryAccessor} === undefined ? undefined : ${converterVar}(${queryAccessor}, {loosely: true});`);
package/src/router.ts CHANGED
@@ -18,7 +18,7 @@ import { MiddlewareRegistry, MiddlewareRegistryEntry } from '@deepkit/app';
18
18
  import { HttpMiddlewareConfig, HttpMiddlewareFn } from './middleware.js';
19
19
 
20
20
  //@ts-ignore
21
- import qs from 'qs';
21
+ import { parseQueryString } from './query-string.js';
22
22
  import { HtmlResponse, JSONResponse, Redirect, Response } from './http.js';
23
23
  import { getRequestParserCodeForParameters, ParameterForRequestParser, parseRoutePathToRegex } from './request-parser.js';
24
24
  import { HttpConfig } from './module.config.js';
@@ -699,7 +699,7 @@ export class HttpRouter {
699
699
  this.buildId = this.registry.getBuildId();
700
700
  const compiler = new CompilerContext;
701
701
  compiler.context.set('ValidationError', ValidationError);
702
- compiler.context.set('qs', qs);
702
+ compiler.context.set('parseQueryString', parseQueryString);
703
703
 
704
704
  const code: string[] = [];
705
705
 
@@ -715,7 +715,7 @@ export class HttpRouter {
715
715
  const _qPosition = _url.indexOf('?');
716
716
  let uploadedFiles = {};
717
717
  const _path = _qPosition === -1 ? _url : _url.substr(0, _qPosition);
718
- const _query = _qPosition === -1 ? {} : qs.parse(_url.substr(_qPosition + 1));
718
+ const _query = _qPosition === -1 ? {} : parseQueryString(_url.substr(_qPosition + 1));
719
719
  ${code.join('\n')}
720
720
  `, 'request') as any;
721
721
  }