@reldens/server-utils 0.33.0 → 0.34.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/README.md CHANGED
@@ -9,6 +9,8 @@ A Node.js server toolkit providing secure application server creation, file hand
9
9
  ### AppServerFactory
10
10
  - Complete Express.js server configuration with modular security
11
11
  - HTTPS/HTTP server creation with SSL certificate management
12
+ - HTTP/2 support via spdy with automatic HTTP/1.1 fallback
13
+ - Optimized static asset caching for CSS, JS, fonts, and images
12
14
  - SNI (Server Name Indication) support for multi-domain hosting
13
15
  - Virtual host management with domain mapping
14
16
  - Development mode detection with appropriate configurations
@@ -99,6 +101,40 @@ if(serverResult){
99
101
  }
100
102
  ```
101
103
 
104
+ ### HTTP/2 Server with Optimized Caching
105
+
106
+ ```javascript
107
+ let appServerFactory = new AppServerFactory();
108
+ let serverResult = appServerFactory.createAppServer({
109
+ port: 443,
110
+ useHttps: true,
111
+ useHttp2: true,
112
+ keyPath: '/ssl/server.key',
113
+ certPath: '/ssl/server.crt',
114
+ autoListen: true
115
+ });
116
+ ```
117
+
118
+ Cache configuration is automatic with defaults:
119
+ - CSS/JS: 1 year
120
+ - Fonts: 1 year
121
+ - Images: 30 days
122
+
123
+ Override cache settings if needed:
124
+
125
+ ```javascript
126
+ let appServerFactory = new AppServerFactory();
127
+ appServerFactory.cacheConfig = {
128
+ '.css': 86400,
129
+ '.js': 86400,
130
+ '.png': 604800
131
+ };
132
+ let serverResult = appServerFactory.createAppServer({
133
+ useHttps: true,
134
+ useHttp2: true
135
+ });
136
+ ```
137
+
102
138
  ### File Operations
103
139
 
104
140
  ```javascript
@@ -193,6 +229,7 @@ appServerFactory.addDomain({
193
229
 
194
230
  let serverResult = appServerFactory.createAppServer({
195
231
  useHttps: true,
232
+ useHttp2: true,
196
233
  useVirtualHosts: true,
197
234
  keyPath: '/ssl/default.key',
198
235
  certPath: '/ssl/default.crt',
@@ -328,6 +365,9 @@ Configurable rate limiting with development mode detection for appropriate thres
328
365
  ### HTTPS Support
329
366
  Full SSL/TLS support with SNI for multi-domain hosting and automatic certificate management.
330
367
 
368
+ ### HTTP/2 Support
369
+ HTTP/2 support via spdy with multiplexing for improved performance and automatic HTTP/1.1 fallback for older clients.
370
+
331
371
  ### Input Validation
332
372
  Built-in validators for common input types including email, username, strong passwords, alphanumeric strings, and IP addresses.
333
373
 
@@ -12,6 +12,7 @@ const { CorsConfigurer } = require('./app-server-factory/cors-configurer');
12
12
  const { RateLimitConfigurer } = require('./app-server-factory/rate-limit-configurer');
13
13
  const http = require('http');
14
14
  const https = require('https');
15
+ const spdy = require('spdy');
15
16
  const express = require('express');
16
17
  const bodyParser = require('body-parser');
17
18
  const session = require('express-session');
@@ -34,6 +35,7 @@ class AppServerFactory
34
35
  this.useUrlencoded = true;
35
36
  this.encoding = 'utf-8';
36
37
  this.useHttps = false;
38
+ this.useHttp2 = false;
37
39
  this.passphrase = '';
38
40
  this.httpsChain = '';
39
41
  this.keyPath = '';
@@ -61,15 +63,28 @@ class AppServerFactory
61
63
  this.defaultDomain = '';
62
64
  this.maxRequestSize = '10mb';
63
65
  this.sanitizeOptions = {allowedTags: [], allowedAttributes: {}};
66
+ this.cacheConfig = {
67
+ '.css': 31536000,
68
+ '.js': 31536000,
69
+ '.woff': 31536000,
70
+ '.woff2': 31536000,
71
+ '.ttf': 31536000,
72
+ '.eot': 31536000,
73
+ '.jpg': 2592000,
74
+ '.jpeg': 2592000,
75
+ '.png': 2592000,
76
+ '.gif': 2592000,
77
+ '.webp': 2592000,
78
+ '.svg': 2592000,
79
+ '.ico': 2592000
80
+ };
64
81
  this.staticOptions = {
65
82
  maxAge: '1d',
83
+ immutable: false,
66
84
  etag: true,
67
85
  lastModified: true,
68
86
  index: false,
69
- setHeaders: function(res){
70
- res.set('X-Content-Type-Options', 'nosniff');
71
- res.set('X-Frame-Options', 'DENY');
72
- }
87
+ setHeaders: this.buildStaticHeaders.bind(this)
73
88
  };
74
89
  this.isDevelopmentMode = false;
75
90
  this.developmentDomains = [];
@@ -98,6 +113,28 @@ class AppServerFactory
98
113
  };
99
114
  }
100
115
 
116
+ buildStaticHeaders(res, path)
117
+ {
118
+ res.set('X-Content-Type-Options', 'nosniff');
119
+ res.set('X-Frame-Options', 'DENY');
120
+ res.set('Vary', 'Accept-Encoding');
121
+ let cacheMaxAge = this.getCacheConfigForPath(path);
122
+ if(cacheMaxAge){
123
+ res.set('Cache-Control', 'public, max-age='+cacheMaxAge+', immutable');
124
+ }
125
+ }
126
+
127
+ getCacheConfigForPath(path)
128
+ {
129
+ let cacheKeys = Object.keys(this.cacheConfig);
130
+ for(let ext of cacheKeys){
131
+ if(path.endsWith(ext)){
132
+ return this.cacheConfig[ext];
133
+ }
134
+ }
135
+ return false;
136
+ }
137
+
101
138
  createAppServer(appServerConfig)
102
139
  {
103
140
  if(appServerConfig){
@@ -117,7 +154,7 @@ class AppServerFactory
117
154
  try {
118
155
  this.appServer = this.createServer();
119
156
  } catch (error) {
120
- this.error = {message: 'Server creation exception: ' + error.message};
157
+ this.error = {message: 'Server creation exception: '+error.message};
121
158
  return false;
122
159
  }
123
160
  if(!this.appServer){
@@ -172,12 +209,14 @@ class AppServerFactory
172
209
  if(!this.isDevelopmentMode){
173
210
  return;
174
211
  }
175
- this.staticOptions.setHeaders = (res) => {
212
+ this.staticOptions.immutable = false;
213
+ this.staticOptions.setHeaders = (res, path) => {
176
214
  res.set('X-Content-Type-Options', 'nosniff');
177
215
  res.set('X-Frame-Options', 'SAMEORIGIN');
178
216
  res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
179
217
  res.set('Pragma', 'no-cache');
180
218
  res.set('Expires', '0');
219
+ res.set('Vary', 'Accept-Encoding');
181
220
  };
182
221
  }
183
222
 
@@ -313,7 +352,7 @@ class AppServerFactory
313
352
  req.domain = this.defaultDomain;
314
353
  return next();
315
354
  }
316
- this.error = {message: 'Unknown domain: ' + hostname};
355
+ this.error = {message: 'Unknown domain: '+hostname};
317
356
  return res.status(404).send('Domain not found');
318
357
  }
319
358
  req.domain = domain;
@@ -343,6 +382,10 @@ class AppServerFactory
343
382
  createServer()
344
383
  {
345
384
  if(!this.useHttps){
385
+ if(this.useHttp2){
386
+ this.error = {message: 'HTTP/2 requires HTTPS to be enabled'};
387
+ return false;
388
+ }
346
389
  return http.createServer(this.app);
347
390
  }
348
391
  if(this.useVirtualHosts && 0 < this.domains.length){
@@ -355,12 +398,12 @@ class AppServerFactory
355
398
  {
356
399
  let key = FileHandler.readFile(this.keyPath, 'Key');
357
400
  if(!key){
358
- this.error = {message: 'Could not read SSL key file: ' + this.keyPath};
401
+ this.error = {message: 'Could not read SSL key file: '+this.keyPath};
359
402
  return false;
360
403
  }
361
404
  let cert = FileHandler.readFile(this.certPath, 'Cert');
362
405
  if(!cert){
363
- this.error = {message: 'Could not read SSL certificate file: ' + this.certPath};
406
+ this.error = {message: 'Could not read SSL certificate file: '+this.certPath};
364
407
  return false;
365
408
  }
366
409
  let credentials = {key, cert, passphrase: this.passphrase};
@@ -370,6 +413,10 @@ class AppServerFactory
370
413
  credentials.ca = ca;
371
414
  }
372
415
  }
416
+ if(this.useHttp2){
417
+ credentials.spdy = {protocols: ['h2', 'http/1.1']};
418
+ return spdy.createServer(credentials, this.app);
419
+ }
373
420
  return https.createServer(credentials, this.app);
374
421
  }
375
422
 
@@ -398,6 +445,10 @@ class AppServerFactory
398
445
  let ctx = tls.createSecureContext({key, cert});
399
446
  callback(null, ctx);
400
447
  };
448
+ if(this.useHttp2){
449
+ httpsOptions.spdy = {protocols: ['h2', 'http/1.1']};
450
+ return spdy.createServer(httpsOptions, this.app);
451
+ }
401
452
  return https.createServer(httpsOptions, this.app);
402
453
  }
403
454
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reldens/server-utils",
3
3
  "scope": "@reldens",
4
- "version": "0.33.0",
4
+ "version": "0.34.0",
5
5
  "description": "Reldens - Server Utils",
6
6
  "author": "Damian A. Pastorini",
7
7
  "license": "MIT",
@@ -17,17 +17,18 @@
17
17
  "utils",
18
18
  "shortcuts",
19
19
  "system",
20
- "game",
21
- "mmorpg",
22
- "rpg",
20
+ "server",
21
+ "http",
22
+ "https",
23
23
  "dwd",
24
- "colyseus",
25
- "phaser",
26
- "parcel",
24
+ "http2",
25
+ "file",
26
+ "encrypt",
27
+ "uploader",
28
+ "upload",
29
+ "cors",
27
30
  "nodejs",
28
- "mmo",
29
- "multiplayer",
30
- "rol",
31
+ "protocol",
31
32
  "platform",
32
33
  "framework"
33
34
  ],
@@ -43,6 +44,7 @@
43
44
  "express-session": "1.18.2",
44
45
  "helmet": "8.1.0",
45
46
  "multer": "2.0.2",
46
- "sanitize-html": "2.17.0"
47
+ "sanitize-html": "2.17.0",
48
+ "spdy": "^4.0.2"
47
49
  }
48
50
  }