slower 2.1.3 → 2.1.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/slower.js +230 -62
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "path-to-regexp": "^6.2.2"
4
4
  },
5
5
  "name": "slower",
6
- "version": "2.1.3",
6
+ "version": "2.1.6",
7
7
  "main": "index.js",
8
8
  "devDependencies": {},
9
9
  "scripts": {
package/src/slower.js CHANGED
@@ -2,6 +2,7 @@
2
2
  const http = require('node:http');
3
3
  const https = require('node:https');
4
4
  const path = require('node:path');
5
+ const fs = require('node:fs');
5
6
  const { createReadStream } = require('node:fs');
6
7
  const { pipeline } = require('node:stream/promises');
7
8
 
@@ -33,20 +34,24 @@ class SlowerRouter {
33
34
  this.layers = new Map();
34
35
 
35
36
  // Create basic route shortcuts
36
- // get(), post(), put(), delete()
37
- // They can be used with either 1 or 2 params
37
+ // get(), post(), put(), delete(), ...
38
+ // They can be used with either 1 or more params
38
39
  /**
39
- * app.get({path}, {handler}) -> apply handler for a specific route
40
+ * app.get({path}, {handler}) -> apply handlers for a specific route
41
+ * app.get({path}, {handler}, {handler}, ...) -> apply handlers for a specific route
40
42
  * or
41
- * app.get({handler}) -> apply handler for any route for a specific method
43
+ * app.get({handler}) -> apply handlers for any route for a specific method
44
+ * app.get({handler}, {handler}, ...) -> apply handlers for any route for a specific method
42
45
  *
43
46
  */
44
47
  for (let verb of HTTP_VERBS) {
45
48
  this.layers.set(verb, new Map());
46
- this[verb] = function (path, callback) {
49
+ this[verb] = function (path, ...callbacks) {
47
50
  if (typeof path === 'function')
48
- return this.#setRoute(verb, MATCH_ANY, path);
49
- return this.#setRoute(verb, path, callback);
51
+ this.#setRoute(verb, MATCH_ANY, path);
52
+ for (let callback of callbacks)
53
+ this.#setRoute(verb, path, callback);
54
+ return this;
50
55
  };
51
56
  }
52
57
 
@@ -67,8 +72,9 @@ class SlowerRouter {
67
72
  // Get all routes that match the URL and join with middlewares to cycle
68
73
  let foundRoutes = utils.getMatchingRoute(req.url, req.method, self.layers);
69
74
  let layers = foundRoutes;
70
- // If there are no layers, add an Error:404 special layer (not found)
71
- if (layers.length === 0) layers.push(utils.noLayersFoundFallback);
75
+ // Add an Error:404 special layer to the end of the layers list
76
+ // This prevents accidental requests hanging
77
+ layers.push(utils.noLayersFoundFallback);
72
78
 
73
79
  // Set properties on request and response objects
74
80
  req = await setupRequest(req);
@@ -109,7 +115,7 @@ class SlowerRouter {
109
115
  * Create a middleware for all HTTP methods, for a specific path
110
116
  * @overload
111
117
  * @param {String} path
112
- * @param {Function} handler
118
+ * @param {...Function} handlers
113
119
  * @returns {SlowerRouter}
114
120
  * @example Applies a middleware for all methods, for a specific path
115
121
  * app.all('/img/:id', (req, res, next) => {console.log(...); next()})
@@ -119,7 +125,7 @@ class SlowerRouter {
119
125
  * @info This is the same as using "app[method]({callback})", without a path. Like: app.get(() => {});
120
126
  * @overload
121
127
  * @param {string} verb (one of the HTTP verbs)
122
- * @param {Function} handler
128
+ * @param {...Function} handlers
123
129
  * @returns {SlowerRouter}
124
130
  * @example Applies a middleware for all GET requests
125
131
  * app.all('get', (req, res, next) => {console.log(...); next()})
@@ -127,28 +133,39 @@ class SlowerRouter {
127
133
  /**
128
134
  * Create a global middleware (all paths and all HTTP methods)
129
135
  * @overload
130
- * @param {Function} handler
136
+ * @param {...Function} handlers
131
137
  * @returns {SlowerRouter}
132
138
  * @example Applies a middleware for all HTTP requests (of any method)
133
139
  * app.all((req, res, next) => {console.log(...); next()})
134
140
  */
135
- all (path, handler) {
136
- // function signature: app.all({METHOD}, {HANDLER})
141
+ all (path, ...handlers) {
142
+
143
+ // function signature: app.all({METHOD}, ...{HANDLERS})
137
144
  // example: app.all('post', () => {});
138
145
  if (typeof path === 'string' && HTTP_VERBS.includes(path.toLowerCase()))
139
- this.#setRoute(path, MATCH_ANY, handler);
146
+ for (let handler of handlers)
147
+ this.#setRoute(path, MATCH_ANY, handler);
148
+
140
149
 
141
- // function signature: app.all({PATH}, {HANDLER})
150
+ // function signature: app.all({PATH}, ...{HANDLERS})
142
151
  // example: app.all('/api', () => {});
143
152
  else if (typeof path === 'string')
144
- for (let verb of HTTP_VERBS) this.#setRoute(verb, path, handler);
145
-
146
- // function signature: app.all({HANDLER})
153
+ for (let handler of handlers)
154
+ for (let verb of HTTP_VERBS)
155
+ this.#setRoute(verb, path, handler);
156
+
157
+ // function signature: app.all(...{HANDLERS})
147
158
  // example: app.all(() => {});
148
159
  else if (typeof path === 'function')
149
- for (let verb of HTTP_VERBS) this.#setRoute(verb, MATCH_ANY, path);
160
+ for (let verb of HTTP_VERBS) {
161
+ this.#setRoute(verb, MATCH_ANY, path);
162
+ for (let handler of handlers)
163
+ this.#setRoute(verb, MATCH_ANY, handler);
164
+ }
150
165
 
166
+
151
167
  else throw new Error('<SlowerRouter>.use :: "handler" parameter must be of type Function');
168
+
152
169
  return this;
153
170
  }
154
171
  // Just a more comprehensive call to app.all for defining middlewares
@@ -171,6 +188,9 @@ class SlowerRouter {
171
188
  */
172
189
  static (directoryPath, mountPath = '') {
173
190
  const absoluteDir = path.resolve(directoryPath);
191
+ if (!fs.existsSync(absoluteDir))
192
+ throw new Error(`Invalid directory provided for [SlowerRouter].static(): [${directoryPath}]`);
193
+
174
194
  for (const file of utils.getFiles(absoluteDir)) {
175
195
  // Get only the file name from the absolute file path 'c:\u\a.txt' -> 'a.txt'
176
196
  let fileAsURLPath = file.replaceAll(/\\/g, '/').split('/').slice(-1)[0];
@@ -238,21 +258,47 @@ class SlowerRouter {
238
258
 
239
259
 
240
260
  /**
241
- * Used as the class for micro-routing with "app.route"
242
- *
243
- * only method acessors (.get(), .post(), .put(), ...)
244
- * and .all() and .use()
245
- *
246
- * .static() is not allowed
261
+ * Used as the class for modular routers
262
+ * used in "slower.Router()"
247
263
  */
248
- class SlowerMicroRouter {
249
- constructor (path, layerPool) {
250
- this.path = path;
251
- this.layers = layerPool;
264
+ class SlowerSubRouter {
265
+ constructor () {
266
+ this.METHODS = HTTP_VERBS;
267
+ this.layers = new Array();
268
+
269
+ // OLD version: (Do not delete until new version is properly tested)
270
+ // Create basic route shortcuts
271
+ // get(), post(), put(), delete()
272
+ // for (let verb of HTTP_VERBS) {
273
+ // this[verb] = function (path, callback) {
274
+ // return this.#setRoute(verb, path, callback);
275
+ // };
276
+ // }
277
+
278
+
279
+ // Create basic route shortcuts
280
+ // get(), post(), put(), delete(), ...
281
+ // They can be used with either 1 or more params
282
+ /**
283
+ * app.get({path}, {handler}) -> apply handlers for a specific route
284
+ * app.get({path}, {handler}, {handler}, ...) -> apply handlers for a specific route
285
+ * or
286
+ * app.get({handler}) -> apply handlers for any route for a specific method
287
+ * app.get({handler}, {handler}, ...) -> apply handlers for any route for a specific method
288
+ *
289
+ */
290
+ for (let verb of HTTP_VERBS) {
291
+ this[verb] = function (path, ...callbacks) {
292
+ if (typeof path === 'function')
293
+ this.#setRoute(verb, MATCH_ANY, path);
294
+ for (let callback of callbacks)
295
+ this.#setRoute(verb, path, callback);
296
+ return this;
297
+ };
298
+ }
252
299
  }
253
300
 
254
- #setRoute (method, handler) {
255
- const path = this.path;
301
+ #setRoute (method, path, handler) {
256
302
  if (typeof method !== 'string')
257
303
  throw new Error('<SlowerSubRouter>.route :: "method" parameter must be of type String');
258
304
  if (typeof path !== 'string' && path?.constructor?.name !== 'RegExp')
@@ -263,66 +309,188 @@ class SlowerMicroRouter {
263
309
  return this;
264
310
  }
265
311
 
266
- all (handler) {
267
- const path = this.path;
268
- if (typeof path === 'string')
269
- for (let verb of HTTP_VERBS) this.#setRoute(verb, path, handler);
270
- else if (typeof path !== 'function')
271
- throw new Error('<SlowerSubRouter>.use :: "handler" parameter must be of type Function');
272
- else for (let verb of HTTP_VERBS) this.#setRoute(verb, '/(.{0,})', path);
312
+ // Add middleware
313
+ /**
314
+ * Create a middleware for all HTTP methods, for a specific path
315
+ * @overload
316
+ * @param {String} path
317
+ * @param {...Function} handlers
318
+ * @returns {SlowerRouter}
319
+ * @example Applies a middleware for all methods, for a specific path
320
+ * app.all('/img/:id', (req, res, next) => {console.log(...); next()})
321
+ */
322
+ /**
323
+ * Create a global middleware for a specific verb (all paths for that method)
324
+ * @info This is the same as using "app[method]({callback})", without a path. Like: app.get(() => {});
325
+ * @overload
326
+ * @param {string} verb (one of the HTTP verbs)
327
+ * @param {...Function} handlers
328
+ * @returns {SlowerRouter}
329
+ * @example Applies a middleware for all GET requests
330
+ * app.all('get', (req, res, next) => {console.log(...); next()})
331
+ */
332
+ /**
333
+ * Create a global middleware (all paths and all HTTP methods)
334
+ * @overload
335
+ * @param {...Function} handlers
336
+ * @returns {SlowerRouter}
337
+ * @example Applies a middleware for all HTTP requests (of any method)
338
+ * app.all((req, res, next) => {console.log(...); next()})
339
+ */
340
+ all (path, ...handlers) {
341
+
342
+ // function signature: app.all({METHOD}, ...{HANDLERS})
343
+ // example: app.all('post', () => {});
344
+ if (typeof path === 'string' && HTTP_VERBS.includes(path.toLowerCase()))
345
+ for (let handler of handlers)
346
+ this.#setRoute(path, MATCH_ANY, handler);
347
+
348
+
349
+ // function signature: app.all({PATH}, ...{HANDLERS})
350
+ // example: app.all('/api', () => {});
351
+ else if (typeof path === 'string')
352
+ for (let handler of handlers)
353
+ for (let verb of HTTP_VERBS)
354
+ this.#setRoute(verb, path, handler);
355
+
356
+ // function signature: app.all(...{HANDLERS})
357
+ // example: app.all(() => {});
358
+ else if (typeof path === 'function')
359
+ for (let verb of HTTP_VERBS) {
360
+ this.#setRoute(verb, MATCH_ANY, path);
361
+ for (let handler of handlers)
362
+ this.#setRoute(verb, MATCH_ANY, handler);
363
+ }
364
+
365
+
366
+ else throw new Error('<SlowerSubRouter>.use :: "handler" parameter must be of type Function');
367
+
273
368
  return this;
274
369
  }
275
370
  // Just a more comprehensive call to app.all for defining middlewares
276
371
  use (...b) { this.all(...b); return this; };
372
+
373
+ static (directoryPath, mountPath = '') {
374
+ this.layers.push({ static: true, directoryPath, mountPath });
375
+ return this;
376
+ }
377
+
378
+ /**
379
+ * Creates a temporary synced mini-router for a specific path
380
+ * Allows to declare multiple handlers for methods of a specific path
381
+ * @param {string} path
382
+ * @returns {SlowerMicroRouter}
383
+ * @example
384
+ * app.route('/books')
385
+ * .get((req, res) => console.log('you retrieved a book with GET'))
386
+ * .post((req, res) => console.log('you added a book with POST'))
387
+ * ;
388
+ */
389
+ route (path) {
390
+ return new SlowerMicroRouter(path, this.layers);
391
+ }
277
392
  }
278
393
 
279
394
 
395
+
280
396
  /**
281
- * Used as the class for modular routers
282
- * used in "slower.Router()"
397
+ * Used as the class for micro-routing with "app.route"
398
+ *
399
+ * only method acessors (.get(), .post(), .put(), ...)
400
+ * and .all() and .use()
401
+ *
402
+ * .static() is not allowed
283
403
  */
284
- class SlowerSubRouter {
285
- constructor () {
286
- this.METHODS = HTTP_VERBS;
287
- this.layers = new Array();
404
+ class SlowerMicroRouter {
405
+ constructor (path, layerPool) {
406
+ this.path = path;
407
+ this.layers = layerPool;
288
408
 
289
409
  // Create basic route shortcuts
290
410
  // get(), post(), put(), delete()
291
411
  for (let verb of HTTP_VERBS) {
292
- this[verb] = function (path, callback) {
293
- return this.#setRoute(verb, path, callback);
412
+ this[verb] = function (...callbacks) {
413
+ for (let callback of callbacks)
414
+ this.#setRoute(verb, callback);
294
415
  };
295
416
  }
296
417
  }
297
418
 
298
- #setRoute (method, path, handler) {
419
+ #setRoute (method, handler) {
420
+ const path = this.path;
299
421
  if (typeof method !== 'string')
300
- throw new Error('<SlowerSubRouter>.route :: "method" parameter must be of type String');
422
+ throw new Error('<SlowerMicroRouter>.route :: "method" parameter must be of type String');
301
423
  if (typeof path !== 'string' && path?.constructor?.name !== 'RegExp')
302
- throw new Error('<SlowerSubRouter>.route :: "path" parameter must be of type Function, String or RegExp');
424
+ throw new Error('<SlowerMicroRouter>.route :: "path" parameter must be of type Function, String or RegExp');
303
425
  if (typeof handler !== 'function')
304
- throw new Error('<SlowerSubRouter>.route :: "handler" parameter must be of type Function');
426
+ throw new Error('<SlowerMicroRouter>.route :: "handler" parameter must be of type Function');
305
427
  this.layers.push({ method, path, handler });
306
428
  return this;
307
429
  }
308
430
 
309
- all (path, handler) {
310
- if (typeof path === 'string')
311
- for (let verb of HTTP_VERBS) this.#setRoute(verb, path, handler);
312
- else if (typeof path !== 'function')
313
- throw new Error('<SlowerSubRouter>.use :: "handler" parameter must be of type Function');
314
- else for (let verb of HTTP_VERBS) this.#setRoute(verb, '/(.{0,})', path);
431
+ // Add middleware
432
+ /**
433
+ * Create a middleware for all HTTP methods, for a specific path
434
+ * @overload
435
+ * @param {String} path
436
+ * @param {...Function} handlers
437
+ * @returns {SlowerRouter}
438
+ * @example Applies a middleware for all methods, for a specific path
439
+ * app.all('/img/:id', (req, res, next) => {console.log(...); next()})
440
+ */
441
+ /**
442
+ * Create a global middleware for a specific verb (all paths for that method)
443
+ * @info This is the same as using "app[method]({callback})", without a path. Like: app.get(() => {});
444
+ * @overload
445
+ * @param {string} verb (one of the HTTP verbs)
446
+ * @param {...Function} handlers
447
+ * @returns {SlowerRouter}
448
+ * @example Applies a middleware for all GET requests
449
+ * app.all('get', (req, res, next) => {console.log(...); next()})
450
+ */
451
+ /**
452
+ * Create a global middleware (all paths and all HTTP methods)
453
+ * @overload
454
+ * @param {...Function} handlers
455
+ * @returns {SlowerRouter}
456
+ * @example Applies a middleware for all HTTP requests (of any method)
457
+ * app.all((req, res, next) => {console.log(...); next()})
458
+ */
459
+ all (path, ...handlers) {
460
+
461
+ // function signature: app.all({METHOD}, ...{HANDLERS})
462
+ // example: app.all('post', () => {});
463
+ if (typeof path === 'string' && HTTP_VERBS.includes(path.toLowerCase()))
464
+ for (let handler of handlers)
465
+ this.#setRoute(path, MATCH_ANY, handler);
466
+
467
+
468
+ // function signature: app.all({PATH}, ...{HANDLERS})
469
+ // example: app.all('/api', () => {});
470
+ else if (typeof path === 'string')
471
+ for (let handler of handlers)
472
+ for (let verb of HTTP_VERBS)
473
+ this.#setRoute(verb, path, handler);
474
+
475
+ // function signature: app.all(...{HANDLERS})
476
+ // example: app.all(() => {});
477
+ else if (typeof path === 'function')
478
+ for (let verb of HTTP_VERBS) {
479
+ this.#setRoute(verb, MATCH_ANY, path);
480
+ for (let handler of handlers)
481
+ this.#setRoute(verb, MATCH_ANY, handler);
482
+ }
483
+
484
+
485
+ else throw new Error('<SlowerMicroRouter>.use :: "handler" parameter must be of type Function');
486
+
315
487
  return this;
316
488
  }
317
489
  // Just a more comprehensive call to app.all for defining middlewares
318
490
  use (...b) { this.all(...b); return this; };
319
-
320
- static (directoryPath, mountPath = '') {
321
- this.layers.push({ static: true, directoryPath, mountPath });
322
- return this;
323
- }
324
491
  }
325
492
 
493
+
326
494
  // Create basic main routing creation
327
495
  function slower (options) {
328
496
  return new SlowerRouter(options);