@e22m4u/js-http-static-router 0.1.2 → 0.2.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.
- package/.mocharc.json +2 -1
- package/README.md +265 -17
- package/build-cjs.js +1 -1
- package/dist/cjs/index.cjs +111 -73
- package/example/server.js +23 -13
- package/mocha.setup.js +4 -0
- package/package.json +4 -2
- package/src/http-static-router.d.ts +7 -2
- package/src/http-static-router.js +70 -58
- package/src/http-static-router.spec.js +899 -0
- package/src/static-route.js +18 -8
- package/src/types.d.ts +7 -0
- package/src/utils/create-cookie-string.d.ts +6 -0
- package/src/utils/create-cookie-string.js +28 -0
- package/src/utils/create-cookie-string.spec.js +32 -0
- package/src/utils/create-error.d.ts +14 -0
- package/src/utils/create-error.js +29 -0
- package/src/utils/create-error.spec.js +42 -0
- package/src/utils/create-request-mock.d.ts +35 -0
- package/src/utils/create-request-mock.js +483 -0
- package/src/utils/create-request-mock.spec.js +646 -0
- package/src/utils/create-response-mock.d.ts +18 -0
- package/src/utils/create-response-mock.js +131 -0
- package/src/utils/create-response-mock.spec.js +150 -0
- package/src/utils/fetch-request-body.d.ts +26 -0
- package/src/utils/fetch-request-body.js +148 -0
- package/src/utils/fetch-request-body.spec.js +209 -0
- package/src/utils/get-pathname-from-url.d.ts +1 -1
- package/src/utils/{get-request-pathname.spec.js → get-pathname-from-url.spec.js} +1 -1
- package/src/utils/index.d.ts +8 -0
- package/src/utils/index.js +8 -0
- package/src/utils/is-readable-stream.d.ts +9 -0
- package/src/utils/is-readable-stream.js +12 -0
- package/src/utils/is-readable-stream.spec.js +23 -0
- package/src/utils/parse-content-type.d.ts +15 -0
- package/src/utils/parse-content-type.js +34 -0
- package/src/utils/parse-content-type.spec.js +79 -0
- package/src/utils/parse-cookie-string.d.ts +19 -0
- package/src/utils/parse-cookie-string.js +36 -0
- package/src/utils/parse-cookie-string.spec.js +45 -0
- package/{example/static → static}/index.html +2 -2
- /package/{example/static/nested/file.txt → static/assets/nested/heart.txt} +0 -0
- /package/{example/static/file.txt → static/assets/rabbit.txt} +0 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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
|
|
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
|
|
182
|
+
var import_js_format9 = require("@e22m4u/js-format");
|
|
152
183
|
var import_js_service = require("@e22m4u/js-service");
|
|
153
|
-
var
|
|
184
|
+
var HttpStaticRouter = class extends import_js_service.DebuggableService {
|
|
185
|
+
static {
|
|
186
|
+
__name(this, "HttpStaticRouter");
|
|
187
|
+
}
|
|
154
188
|
/**
|
|
155
189
|
* Routes.
|
|
156
190
|
*
|
|
@@ -180,9 +214,9 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
|
|
|
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
|
|
184
|
-
|
|
185
|
-
|
|
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
222
|
super(void 0, debugOptions);
|
|
@@ -195,20 +229,20 @@ var _HttpStaticRouter = class _HttpStaticRouter extends import_js_service.Debugg
|
|
|
195
229
|
}
|
|
196
230
|
if (options !== void 0) {
|
|
197
231
|
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
198
|
-
throw new
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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
|
-
|
|
309
|
-
targetPath = import_path2.default.join(route.resourcePath,
|
|
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 (
|
|
373
|
+
if (extraPath && extraPath.endsWith("/")) {
|
|
328
374
|
continue;
|
|
329
375
|
}
|
|
330
|
-
debug("
|
|
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
|
-
|
|
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.
|
|
363
|
-
|
|
364
|
-
|
|
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
|
-
|
|
376
|
-
|
|
429
|
+
if (!response.writableFinished) {
|
|
430
|
+
debug("Request closed prematurely by the client.");
|
|
431
|
+
fileStream.destroy();
|
|
432
|
+
resolve();
|
|
433
|
+
}
|
|
377
434
|
});
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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
|
-
//
|
|
13
|
-
//
|
|
13
|
+
// объявление файла "index.html"
|
|
14
|
+
// в качестве индексной страницы
|
|
14
15
|
staticRouter.defineRoute({
|
|
15
|
-
remotePath: '/
|
|
16
|
-
resourcePath: './
|
|
16
|
+
remotePath: '/',
|
|
17
|
+
resourcePath: './index.html',
|
|
17
18
|
});
|
|
18
19
|
|
|
19
|
-
// объявление файла "
|
|
20
|
-
//
|
|
20
|
+
// объявление файла "page.html"
|
|
21
|
+
// доступным по адресу "/page"
|
|
21
22
|
staticRouter.defineRoute({
|
|
22
|
-
remotePath: '/
|
|
23
|
-
resourcePath: './
|
|
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
|
|
42
|
-
console.log('http://localhost:3000/
|
|
43
|
-
console.log('http://localhost:3000/
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-http-static-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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": ">=
|
|
27
|
+
"node": ">=18"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"lint": "tsc && eslint ./src",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@e22m4u/js-format": "~0.4.0",
|
|
41
41
|
"@e22m4u/js-service": "~0.6.1",
|
|
42
|
+
"http-errors": "~2.0.1",
|
|
42
43
|
"mime-types": "~3.0.2"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"@types/mocha": "~10.0.10",
|
|
50
51
|
"c8": "~11.0.0",
|
|
51
52
|
"chai": "~6.2.2",
|
|
53
|
+
"chai-as-promised": "~8.0.2",
|
|
52
54
|
"esbuild": "~0.27.3",
|
|
53
55
|
"eslint": "~9.39.2",
|
|
54
56
|
"eslint-config-prettier": "~10.1.8",
|
|
@@ -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):
|
|
49
|
+
defineRoute(routeDef: StaticRouteDefinition): StaticRoute;
|
|
45
50
|
|
|
46
51
|
/**
|
|
47
52
|
* Handle request.
|