@e22m4u/js-http-static-router 0.1.2 → 0.2.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 (43) hide show
  1. package/.mocharc.json +2 -1
  2. package/README.md +265 -17
  3. package/build-cjs.js +1 -1
  4. package/dist/cjs/index.cjs +114 -76
  5. package/example/server.js +23 -13
  6. package/mocha.setup.js +4 -0
  7. package/package.json +10 -8
  8. package/src/http-static-router.d.ts +7 -2
  9. package/src/http-static-router.js +73 -61
  10. package/src/http-static-router.spec.js +899 -0
  11. package/src/static-route.js +18 -8
  12. package/src/types.d.ts +7 -0
  13. package/src/utils/create-cookie-string.d.ts +6 -0
  14. package/src/utils/create-cookie-string.js +28 -0
  15. package/src/utils/create-cookie-string.spec.js +32 -0
  16. package/src/utils/create-error.d.ts +14 -0
  17. package/src/utils/create-error.js +29 -0
  18. package/src/utils/create-error.spec.js +42 -0
  19. package/src/utils/create-request-mock.d.ts +35 -0
  20. package/src/utils/create-request-mock.js +483 -0
  21. package/src/utils/create-request-mock.spec.js +646 -0
  22. package/src/utils/create-response-mock.d.ts +18 -0
  23. package/src/utils/create-response-mock.js +131 -0
  24. package/src/utils/create-response-mock.spec.js +150 -0
  25. package/src/utils/fetch-request-body.d.ts +26 -0
  26. package/src/utils/fetch-request-body.js +148 -0
  27. package/src/utils/fetch-request-body.spec.js +209 -0
  28. package/src/utils/get-pathname-from-url.d.ts +1 -1
  29. package/src/utils/{get-request-pathname.spec.js → get-pathname-from-url.spec.js} +1 -1
  30. package/src/utils/index.d.ts +8 -0
  31. package/src/utils/index.js +8 -0
  32. package/src/utils/is-readable-stream.d.ts +9 -0
  33. package/src/utils/is-readable-stream.js +12 -0
  34. package/src/utils/is-readable-stream.spec.js +23 -0
  35. package/src/utils/parse-content-type.d.ts +15 -0
  36. package/src/utils/parse-content-type.js +34 -0
  37. package/src/utils/parse-content-type.spec.js +79 -0
  38. package/src/utils/parse-cookie-string.d.ts +19 -0
  39. package/src/utils/parse-cookie-string.js +36 -0
  40. package/src/utils/parse-cookie-string.spec.js +45 -0
  41. package/{example/static → static}/index.html +2 -2
  42. /package/{example/static/nested/file.txt → static/assets/nested/heart.txt} +0 -0
  43. /package/{example/static/file.txt → static/assets/rabbit.txt} +0 -0
@@ -48,7 +48,10 @@ __name(escapeRegexp, "escapeRegexp");
48
48
 
49
49
  // src/static-route.js
50
50
  var import_js_format = require("@e22m4u/js-format");
51
- var _StaticRoute = class _StaticRoute {
51
+ var StaticRoute = class {
52
+ static {
53
+ __name(this, "StaticRoute");
54
+ }
52
55
  /**
53
56
  * Remote path.
54
57
  *
@@ -93,7 +96,7 @@ var _StaticRoute = class _StaticRoute {
93
96
  }
94
97
  if (!routeDef.remotePath.startsWith("/")) {
95
98
  throw new import_js_format.InvalidArgumentError(
96
- 'Option "remotePath" must starts with "/", but %v was given.',
99
+ 'Option "remotePath" must start with "/", but %v was given.',
97
100
  routeDef.remotePath
98
101
  );
99
102
  }
@@ -103,42 +106,70 @@ var _StaticRoute = class _StaticRoute {
103
106
  routeDef.resourcePath
104
107
  );
105
108
  }
106
- const resourcePath = import_path.default.resolve(routeDef.resourcePath);
109
+ if (!import_path.default.isAbsolute(routeDef.resourcePath)) {
110
+ throw new import_js_format.InvalidArgumentError(
111
+ 'Option "resourcePath" must be an absolute path, but %v was given.',
112
+ routeDef.resourcePath
113
+ );
114
+ }
107
115
  let stats;
108
116
  try {
109
- stats = import_fs.default.statSync(resourcePath);
117
+ stats = import_fs.default.statSync(routeDef.resourcePath);
110
118
  } catch (error) {
111
119
  console.error(error);
112
120
  throw new import_js_format.InvalidArgumentError(
113
121
  "Resource path %v does not exist.",
114
- resourcePath
122
+ routeDef.resourcePath
115
123
  );
116
124
  }
117
125
  const isFile = stats.isFile();
118
126
  const escapedRemotePath = escapeRegexp(routeDef.remotePath);
119
- const regexp = isFile ? new RegExp(`^${escapedRemotePath}$`) : new RegExp(`^${escapedRemotePath}(?:$|\\/)`);
127
+ let regexp;
128
+ if (isFile) {
129
+ regexp = new RegExp(`^${escapedRemotePath}$`);
130
+ } else if (escapedRemotePath === "/") {
131
+ regexp = new RegExp(`^(?:$|\\/)`);
132
+ } else {
133
+ regexp = new RegExp(`^${escapedRemotePath}(?:$|\\/)`);
134
+ }
120
135
  this.remotePath = routeDef.remotePath;
121
- this.resourcePath = resourcePath;
136
+ this.resourcePath = routeDef.resourcePath;
122
137
  this.regexp = regexp;
123
138
  this.isFile = isFile;
124
139
  }
125
140
  };
126
- __name(_StaticRoute, "StaticRoute");
127
- var StaticRoute = _StaticRoute;
128
141
 
129
142
  // src/http-static-router.js
130
143
  var import_path2 = __toESM(require("path"), 1);
131
144
  var import_mime_types = __toESM(require("mime-types"), 1);
132
- var import_http = require("http");
133
145
  var import_fs2 = __toESM(require("fs"), 1);
134
146
 
135
- // src/utils/get-pathname-from-url.js
147
+ // src/utils/create-error.js
136
148
  var import_js_format2 = require("@e22m4u/js-format");
149
+
150
+ // src/utils/fetch-request-body.js
151
+ var import_http_errors = __toESM(require("http-errors"), 1);
152
+ var import_js_format4 = require("@e22m4u/js-format");
153
+
154
+ // src/utils/parse-content-type.js
155
+ var import_js_format3 = require("@e22m4u/js-format");
156
+
157
+ // src/utils/create-request-mock.js
158
+ var import_js_format7 = require("@e22m4u/js-format");
159
+
160
+ // src/utils/parse-cookie-string.js
161
+ var import_js_format5 = require("@e22m4u/js-format");
162
+
163
+ // src/utils/create-cookie-string.js
164
+ var import_js_format6 = require("@e22m4u/js-format");
165
+
166
+ // src/utils/get-pathname-from-url.js
167
+ var import_js_format8 = require("@e22m4u/js-format");
137
168
  var HOST_RE = /^https?:\/\/[^/]+/;
138
169
  var QUERY_STRING_RE = /\?.*$/;
139
170
  function getPathnameFromUrl(url) {
140
171
  if (typeof url !== "string") {
141
- throw new import_js_format2.InvalidArgumentError(
172
+ throw new import_js_format8.InvalidArgumentError(
142
173
  'Parameter "url" must be a String, but %v was given.',
143
174
  url
144
175
  );
@@ -148,9 +179,12 @@ function getPathnameFromUrl(url) {
148
179
  __name(getPathnameFromUrl, "getPathnameFromUrl");
149
180
 
150
181
  // src/http-static-router.js
151
- var import_js_format3 = require("@e22m4u/js-format");
182
+ var import_js_format9 = require("@e22m4u/js-format");
152
183
  var import_js_service = require("@e22m4u/js-service");
153
- var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.DebuggableService {
184
+ var HttpStaticRouter = class extends import_js_service.DebuggableService {
185
+ static {
186
+ __name(this, "HttpStaticRouter");
187
+ }
154
188
  /**
155
189
  * Routes.
156
190
  *
@@ -173,42 +207,42 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
173
207
  */
174
208
  constructor(containerOrOptions, options) {
175
209
  const debugOptions = {
176
- noEnvironmentNamespace: true,
210
+ noGlobalNamespace: true,
177
211
  namespace: "jsHttpStaticRouter"
178
212
  };
179
213
  if ((0, import_js_service.isServiceContainer)(containerOrOptions)) {
180
214
  super(containerOrOptions, debugOptions);
181
215
  } else if (containerOrOptions !== void 0) {
182
216
  if (!containerOrOptions || typeof containerOrOptions !== "object" || Array.isArray(containerOrOptions)) {
183
- throw new import_js_format3.InvalidArgumentError(
184
- 'Parameter "containerOrOptions" must be an Object or an instance of ServiceContainer, but %v was given.',
185
- options
217
+ throw new import_js_format9.InvalidArgumentError(
218
+ "First parameter must be an Object or an instance of ServiceContainer, but %v was given.",
219
+ containerOrOptions
186
220
  );
187
221
  }
188
- super(void 0, debugOptions);
222
+ super(debugOptions);
189
223
  if (options === void 0) {
190
224
  options = containerOrOptions;
191
225
  containerOrOptions = void 0;
192
226
  }
193
227
  } else {
194
- super(void 0, debugOptions);
228
+ super(debugOptions);
195
229
  }
196
230
  if (options !== void 0) {
197
231
  if (!options || typeof options !== "object" || Array.isArray(options)) {
198
- throw new import_js_format3.InvalidArgumentError(
232
+ throw new import_js_format9.InvalidArgumentError(
199
233
  'Parameter "options" must be an Object, but %v was given.',
200
234
  options
201
235
  );
202
236
  }
203
237
  if (options.baseDir !== void 0) {
204
238
  if (typeof options.baseDir !== "string") {
205
- throw new import_js_format3.InvalidArgumentError(
239
+ throw new import_js_format9.InvalidArgumentError(
206
240
  'Option "baseDir" must be a String, but %v was given.',
207
241
  options.baseDir
208
242
  );
209
243
  }
210
244
  if (!import_path2.default.isAbsolute(options.baseDir)) {
211
- throw new import_js_format3.InvalidArgumentError(
245
+ throw new import_js_format9.InvalidArgumentError(
212
246
  'Option "baseDir" must be an absolute path, but %v was given.',
213
247
  options.baseDir
214
248
  );
@@ -222,15 +256,21 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
222
256
  * Define route.
223
257
  *
224
258
  * @param {import('./static-route.js').StaticRouteDefinition} routeDef
225
- * @returns {this}
259
+ * @returns {import('./static-route.js').StaticRoute}
226
260
  */
227
261
  defineRoute(routeDef) {
228
262
  if (!routeDef || typeof routeDef !== "object" || Array.isArray(routeDef)) {
229
- throw new import_js_format3.InvalidArgumentError(
263
+ throw new import_js_format9.InvalidArgumentError(
230
264
  'Parameter "routeDef" must be an Object, but %v was given.',
231
265
  routeDef
232
266
  );
233
267
  }
268
+ if (typeof routeDef.resourcePath !== "string") {
269
+ throw new import_js_format9.InvalidArgumentError(
270
+ 'Option "resourcePath" must be a String, but %v was given.',
271
+ routeDef.resourcePath
272
+ );
273
+ }
234
274
  if (this._options.baseDir !== void 0 && !import_path2.default.isAbsolute(routeDef.resourcePath)) {
235
275
  routeDef = { ...routeDef };
236
276
  routeDef.resourcePath = import_path2.default.join(
@@ -238,19 +278,30 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
238
278
  routeDef.resourcePath
239
279
  );
240
280
  }
281
+ if (this._options.baseDir === void 0 && !import_path2.default.isAbsolute(routeDef.resourcePath)) {
282
+ throw new import_js_format9.InvalidArgumentError(
283
+ 'Option "resourcePath" must be an absolute path when the router option "basePath" is not specified, but %v was given.',
284
+ routeDef.resourcePath
285
+ );
286
+ }
241
287
  const debug = this.getDebuggerFor(this.defineRoute);
242
288
  const route = new StaticRoute(routeDef);
243
289
  debug("Adding a new route.");
244
- debug("Resource path is %v.", route.resourcePath);
245
290
  debug("Remote path is %v.", route.remotePath);
291
+ debug("Resource path is %v.", route.resourcePath);
246
292
  debug("Resource type is %s.", route.isFile ? "File" : "Folder");
247
293
  this._routes.push(route);
248
294
  this._routes.sort((a, b) => b.remotePath.length - a.remotePath.length);
249
- return this;
295
+ return route;
250
296
  }
251
297
  /**
252
298
  * Handle request.
253
299
  *
300
+ * Метод возвращает Promise, который разрешается как:
301
+ * - false, если маршрут не совпал, файл не найден
302
+ * или метод запроса не поддерживается;
303
+ * - true, во всех остальных случаях;
304
+ *
254
305
  * @param {import('http').IncomingMessage} request
255
306
  * @param {import('http').ServerResponse} response
256
307
  * @returns {Promise<boolean>}
@@ -258,7 +309,7 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
258
309
  async handleRequest(request, response) {
259
310
  const fileInfo = await this._findFileForRequest(request);
260
311
  if (fileInfo !== void 0) {
261
- this._sendFile(request, response, fileInfo);
312
+ await this._sendFile(request, response, fileInfo);
262
313
  return true;
263
314
  }
264
315
  return false;
@@ -270,12 +321,6 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
270
321
  * @returns {Promise<FileInfo|undefined>|undefined}
271
322
  */
272
323
  async _findFileForRequest(request) {
273
- if (!(request instanceof import_http.IncomingMessage)) {
274
- throw new import_js_format3.InvalidArgumentError(
275
- 'Parameter "request" must be an instance of IncomingMessage, but %v was given.',
276
- request
277
- );
278
- }
279
324
  const debug = this.getDebuggerFor(this._findFileForRequest);
280
325
  debug("File finding for an incoming request.");
281
326
  debug("Incoming request %s %v.", request.method, request.url);
@@ -300,13 +345,14 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
300
345
  }
301
346
  debug("Walking through %v routes.", this._routes.length);
302
347
  for (const route of this._routes) {
303
- const isMatched = route.regexp.test(requestPath);
348
+ const isMatched = route.regexp.test(requestPath || "/");
304
349
  if (isMatched) {
305
350
  debug("Matched route %v.", route.remotePath);
306
351
  let targetPath = route.resourcePath;
352
+ let extraPath = "";
307
353
  if (!route.isFile) {
308
- const relativePath = requestPath.replace(route.regexp, "");
309
- targetPath = import_path2.default.join(route.resourcePath, relativePath);
354
+ extraPath = requestPath.replace(route.regexp, "");
355
+ targetPath = import_path2.default.join(route.resourcePath, extraPath);
310
356
  }
311
357
  targetPath = import_path2.default.resolve(targetPath);
312
358
  const resourceRoot = import_path2.default.resolve(route.resourcePath);
@@ -324,15 +370,15 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
324
370
  });
325
371
  });
326
372
  if (fileSize !== void 0) {
327
- if (requestPath.endsWith("/")) {
373
+ if (extraPath && extraPath.endsWith("/")) {
328
374
  continue;
329
375
  }
330
- debug("File found %v.", targetPath);
376
+ debug("Found file %v.", targetPath);
331
377
  return { path: targetPath, size: fileSize };
332
378
  }
333
379
  }
334
380
  }
335
- debug("File not found.");
381
+ debug("File was not found.");
336
382
  }
337
383
  /**
338
384
  * Send file.
@@ -340,29 +386,37 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
340
386
  * @param {import('http').IncomingMessage} request
341
387
  * @param {import('http').ServerResponse} response
342
388
  * @param {FileInfo} fileInfo
389
+ * @returns {Promise<void>}
343
390
  */
344
- _sendFile(request, response, fileInfo) {
391
+ async _sendFile(request, response, fileInfo) {
392
+ let resolve;
393
+ const promise = new Promise((res) => resolve = res);
345
394
  const debug = this.getDebuggerFor(this._sendFile);
346
395
  debug("File sending for an incoming request.");
347
396
  debug("Incoming request %s %v.", request.method, request.url);
348
397
  debug("File path %v.", fileInfo.path);
349
398
  debug("File size %v bytes.", fileInfo.size);
350
- if (request.method !== "GET" && request.method !== "HEAD") {
351
- debug("Method not allowed.");
352
- return;
353
- }
354
399
  const extname = import_path2.default.extname(fileInfo.path);
355
400
  const contentType = import_mime_types.default.contentType(extname) || "application/octet-stream";
356
401
  const fileStream = (0, import_fs2.createReadStream)(fileInfo.path);
357
402
  fileStream.on("error", (error) => {
358
403
  debug("Unable to open a file stream.");
359
- this._handleFsError(error, response);
404
+ console.error(error);
405
+ if (response.headersSent) {
406
+ response.destroy();
407
+ resolve();
408
+ return;
409
+ }
410
+ response.statusCode = 500;
411
+ response.setHeader("Content-Type", "text/plain; charset=utf-8");
412
+ response.write("500 Internal Server Error");
413
+ response.end();
414
+ resolve();
360
415
  });
361
416
  fileStream.on("open", () => {
362
- response.writeHead(200, {
363
- "Content-Type": contentType,
364
- "Content-Length": fileInfo.size
365
- });
417
+ response.statusCode = 200;
418
+ response.setHeader("Content-Type", contentType);
419
+ response.setHeader("Content-Length", fileInfo.size);
366
420
  if (request.method === "HEAD") {
367
421
  response.end();
368
422
  debug("Response has been sent without a body for the HEAD request.");
@@ -372,35 +426,19 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
372
426
  fileStream.pipe(response);
373
427
  });
374
428
  request.on("close", () => {
375
- debug("File has been sent.");
376
- fileStream.destroy();
429
+ if (!response.writableFinished) {
430
+ debug("Request closed prematurely by the client.");
431
+ fileStream.destroy();
432
+ resolve();
433
+ }
377
434
  });
378
- }
379
- /**
380
- * Handle filesystem error.
381
- *
382
- * @param {object} error
383
- * @param {object} response
384
- * @returns {undefined}
385
- */
386
- _handleFsError(error, response) {
387
- if (response.headersSent) {
388
- response.destroy();
389
- return;
390
- }
391
- if ("code" in error && error.code === "ENOENT") {
392
- response.writeHead(404, { "Content-Type": "text/plain" });
393
- response.write("404 Not Found");
394
- response.end();
395
- } else {
396
- response.writeHead(500, { "Content-Type": "text/plain" });
397
- response.write("500 Internal Server Error");
398
- response.end();
399
- }
435
+ response.on("finish", () => {
436
+ debug("File has been sent successfully.");
437
+ resolve();
438
+ });
439
+ return promise;
400
440
  }
401
441
  };
402
- __name(_HttpStaticRouter, "HttpStaticRouter");
403
- var HttpStaticRouter = _HttpStaticRouter;
404
442
  // Annotate the CommonJS export names for ESM import in node:
405
443
  0 && (module.exports = {
406
444
  HttpStaticRouter,
package/example/server.js CHANGED
@@ -1,3 +1,4 @@
1
+ import path from 'path';
1
2
  import http from 'http';
2
3
  import {HttpStaticRouter} from '@e22m4u/js-http-static-router';
3
4
 
@@ -6,25 +7,33 @@ const staticRouter = new HttpStaticRouter({
6
7
  // при использовании опции "baseDir", относительные пути
7
8
  // в регистрируемых маршрутах будут разрешаться относительно
8
9
  // указанного адреса файловой системы
9
- baseDir: import.meta.dirname,
10
+ baseDir: path.join(import.meta.dirname, '../static'),
10
11
  });
11
12
 
12
- // экспозиция содержимого директории "/static"
13
- // для доступа по адресу "/assets/{file_name}"
13
+ // объявление файла "index.html"
14
+ // в качестве индексной страницы
14
15
  staticRouter.defineRoute({
15
- remotePath: '/assets', // путь маршрута
16
- resourcePath: './static', // файловый путь
16
+ remotePath: '/',
17
+ resourcePath: './index.html',
17
18
  });
18
19
 
19
- // объявление файла "./index.html"
20
- // для доступа по адресу "/home"
20
+ // объявление файла "page.html"
21
+ // доступным по адресу "/page"
21
22
  staticRouter.defineRoute({
22
- remotePath: '/home',
23
- resourcePath: './static/index.html',
23
+ remotePath: '/page',
24
+ resourcePath: './page.html',
25
+ });
26
+
27
+ // экспозиция содержимого директории "assets"
28
+ // для доступа относительно корня
29
+ // пример: http://localhost:3000/assets/rabbit.txt
30
+ staticRouter.defineRoute({
31
+ remotePath: '/',
32
+ resourcePath: './assets',
24
33
  });
25
34
 
26
35
  // создание HTTP сервера и определение
27
- // функции для обработки запросов
36
+ // слушателя для обработки запросов
28
37
  const server = new http.Server();
29
38
  server.on('request', async (req, res) => {
30
39
  const fileSent = await staticRouter.handleRequest(req, res);
@@ -38,7 +47,8 @@ server.on('request', async (req, res) => {
38
47
  server.listen(3000, () => {
39
48
  console.log('Server is running on http://localhost:3000');
40
49
  console.log('Try to open:');
41
- console.log('http://localhost:3000/home');
42
- console.log('http://localhost:3000/assets/file.txt');
43
- console.log('http://localhost:3000/assets/nested/file.txt');
50
+ console.log('http://localhost:3000');
51
+ console.log('http://localhost:3000/page');
52
+ console.log('http://localhost:3000/rabbit.txt');
53
+ console.log('http://localhost:3000/nested/heart.txt');
44
54
  });
package/mocha.setup.js ADDED
@@ -0,0 +1,4 @@
1
+ import * as chai from 'chai';
2
+ import chaiAsPromised from 'chai-as-promised';
3
+
4
+ chai.use(chaiAsPromised);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-http-static-router",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "HTTP-маршрутизатор статичных ресурсов для Node.js",
5
5
  "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
6
6
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  "require": "./dist/cjs/index.cjs"
25
25
  },
26
26
  "engines": {
27
- "node": ">=12"
27
+ "node": ">=18"
28
28
  },
29
29
  "scripts": {
30
30
  "lint": "tsc && eslint ./src",
@@ -38,23 +38,25 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@e22m4u/js-format": "~0.4.0",
41
- "@e22m4u/js-service": "~0.6.1",
41
+ "@e22m4u/js-service": "~0.6.2",
42
+ "http-errors": "~2.0.1",
42
43
  "mime-types": "~3.0.2"
43
44
  },
44
45
  "devDependencies": {
45
- "@commitlint/cli": "~20.4.3",
46
- "@commitlint/config-conventional": "~20.4.3",
46
+ "@commitlint/cli": "~20.4.4",
47
+ "@commitlint/config-conventional": "~20.4.4",
47
48
  "@eslint/js": "~9.39.2",
48
49
  "@types/chai": "~5.2.3",
49
50
  "@types/mocha": "~10.0.10",
50
51
  "c8": "~11.0.0",
51
52
  "chai": "~6.2.2",
52
- "esbuild": "~0.27.3",
53
+ "chai-as-promised": "~8.0.2",
54
+ "esbuild": "~0.27.4",
53
55
  "eslint": "~9.39.2",
54
56
  "eslint-config-prettier": "~10.1.8",
55
- "eslint-plugin-chai-expect": "~3.1.0",
57
+ "eslint-plugin-chai-expect": "~4.0.0",
56
58
  "eslint-plugin-import": "~2.32.0",
57
- "eslint-plugin-jsdoc": "~62.7.1",
59
+ "eslint-plugin-jsdoc": "~62.8.0",
58
60
  "eslint-plugin-mocha": "~11.2.0",
59
61
  "globals": "~17.4.0",
60
62
  "husky": "~9.1.7",
@@ -1,6 +1,6 @@
1
1
  import {ServerResponse} from 'node:http';
2
2
  import {IncomingMessage} from 'node:http';
3
- import {StaticRouteDefinition} from './static-route.js';
3
+ import {StaticRoute, StaticRouteDefinition} from './static-route.js';
4
4
  import {DebuggableService, ServiceContainer} from '@e22m4u/js-service';
5
5
 
6
6
  /**
@@ -14,6 +14,11 @@ export type HttpStaticRouterOptions = {
14
14
  * Http static router.
15
15
  */
16
16
  export declare class HttpStaticRouter extends DebuggableService {
17
+ /**
18
+ * Constructor.
19
+ */
20
+ constructor();
21
+
17
22
  /**
18
23
  * Constructor.
19
24
  *
@@ -41,7 +46,7 @@ export declare class HttpStaticRouter extends DebuggableService {
41
46
  *
42
47
  * @param routeDef
43
48
  */
44
- defineRoute(routeDef: StaticRouteDefinition): this;
49
+ defineRoute(routeDef: StaticRouteDefinition): StaticRoute;
45
50
 
46
51
  /**
47
52
  * Handle request.