proteum 2.1.6 → 2.1.8

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.
@@ -95,6 +95,9 @@ export type TApiResponseData = { data: any; triggers?: { [cle: string]: any } };
95
95
 
96
96
  export type HttpHeaders = { [cle: string]: string };
97
97
 
98
+ const dynamicHtmlCacheControl = 'no-store, no-cache, must-revalidate, proxy-revalidate';
99
+ const staticHtmlCacheControl = 'public, max-age=0, must-revalidate';
100
+
98
101
  /*----------------------------------
99
102
  - SERVICE CONFIG
100
103
  ----------------------------------*/
@@ -571,14 +574,10 @@ export default class ServerRouter<
571
574
  - RESOLUTION
572
575
  ----------------------------------*/
573
576
  public async middleware(req: express.Request, res: express.Response) {
574
- // Don't cache HTML, because in case of update, assets file name will change (hash.ext)
575
- // https://github.com/helmetjs/nocache/blob/main/index.ts
576
- res.setHeader('Surrogate-Control', 'no-store');
577
- res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
578
-
579
577
  // Create request
580
578
  let requestId = uuid();
581
579
  const cachedPage = req.headers['bypasscache'] ? undefined : this.cache[req.path];
580
+ this.applyHtmlCacheHeaders(res, Boolean(cachedPage));
582
581
  const headers: HttpHeaders = Object.fromEntries(
583
582
  Object.entries(req.headers).map(([key, value]) => [key, Array.isArray(value) ? value.join(', ') : value || '']),
584
583
  );
@@ -638,10 +637,39 @@ export default class ServerRouter<
638
637
  // Static pages
639
638
  if (cachedPage) {
640
639
  console.log('[router] Get static page from cache', req.path);
640
+ res.status(response.statusCode);
641
+ res.header(response.headers);
642
+
643
+ if (response.headers['Location']) {
644
+ res.send(response.data === undefined ? '' : response.data);
645
+ this.app.container.Trace.record(
646
+ request.id,
647
+ 'response.send',
648
+ {
649
+ cached: true,
650
+ statusCode: response.statusCode,
651
+ contentType: response.headers['Content-Type'] || '',
652
+ headerKeys: Object.keys(response.headers),
653
+ redirected: true,
654
+ },
655
+ 'summary',
656
+ );
657
+ this.app.container.Trace.finishRequest(request.id, {
658
+ statusCode: response.statusCode,
659
+ user: request.user?.email,
660
+ });
661
+ return;
662
+ }
663
+
641
664
  this.app.container.Trace.record(
642
665
  request.id,
643
666
  'response.send',
644
- { cached: true, statusCode: response.statusCode, contentType: 'text/html' },
667
+ {
668
+ cached: true,
669
+ statusCode: response.statusCode,
670
+ contentType: response.headers['Content-Type'] || 'text/html',
671
+ headerKeys: Object.keys(response.headers),
672
+ },
645
673
  'summary',
646
674
  );
647
675
  res.send(cachedPage.rendered);
@@ -870,6 +898,12 @@ export default class ServerRouter<
870
898
  }
871
899
 
872
900
  this.app.container.Trace.record(request.id, 'resolve.routes-evaluated', routeStats, 'resolve');
901
+
902
+ if (isStatic) {
903
+ resolve(response);
904
+ return;
905
+ }
906
+
873
907
  this.app.container.Trace.record(request.id, 'resolve.not-found', { path: request.path }, 'summary');
874
908
  reject(new NotFound());
875
909
  } catch (error) {
@@ -923,10 +957,19 @@ export default class ServerRouter<
923
957
  await response.runController(route);
924
958
  if (!response.wasProvided) return;
925
959
 
926
- // Set in cache
927
- if (response.request.path && route.options.static && route.options.static.urls.includes('*')) {
928
- console.log('[router] Set in cache', response.request.path);
929
- this.renderStatic(response.request.path, route.options.static, response.data);
960
+ if (response.request.path && route.options.static) {
961
+ const staticUrls = route.options.static.urls.includes('*') ? [response.request.path] : route.options.static.urls;
962
+
963
+ for (const staticUrl of staticUrls) {
964
+ if (!staticUrl) continue;
965
+
966
+ console.log('[router] Set in cache', staticUrl);
967
+ void this.renderStatic(
968
+ staticUrl,
969
+ route.options.static,
970
+ staticUrl === response.request.path ? response.data : undefined,
971
+ );
972
+ }
930
973
  }
931
974
 
932
975
  const timeEndResolving = Date.now();
@@ -1008,4 +1051,17 @@ export default class ServerRouter<
1008
1051
 
1009
1052
  return response;
1010
1053
  }
1054
+
1055
+ private applyHtmlCacheHeaders(res: express.Response, isStaticHtml: boolean) {
1056
+ if (isStaticHtml) {
1057
+ res.removeHeader('Surrogate-Control');
1058
+ res.setHeader('Cache-Control', staticHtmlCacheControl);
1059
+ return;
1060
+ }
1061
+
1062
+ // Don't cache dynamic HTML, because updated releases can change asset hashes.
1063
+ // https://github.com/helmetjs/nocache/blob/main/index.ts
1064
+ res.setHeader('Surrogate-Control', 'no-store');
1065
+ res.setHeader('Cache-Control', dynamicHtmlCacheControl);
1066
+ }
1011
1067
  }
@@ -34,12 +34,10 @@ export default class DocumentRenderer<TRouter extends TServerRouter> {
34
34
  <head>
35
35
  {/* Format */}
36
36
  <meta charSet="utf-8" />
37
- <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
37
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
38
38
 
39
39
  {/* CSS */}
40
40
  {this.clientStyles()}
41
- <link rel="preload" as="font" href={'/public/icons.woff2?v=' + BUILD_ID} type="font/woff2" />
42
- <link rel="stylesheet" type="text/css" href="/public/icons.css" />
43
41
 
44
42
  {/* JS */}
45
43
  <script
@@ -69,7 +67,7 @@ export default class DocumentRenderer<TRouter extends TServerRouter> {
69
67
  {/* Format */}
70
68
  <meta charSet="utf-8" />
71
69
  <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
72
- <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
70
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
73
71
 
74
72
  {/* Mobile */}
75
73
  <meta name="application-name" content={this.app.identity.web.title} />
@@ -80,18 +78,28 @@ export default class DocumentRenderer<TRouter extends TServerRouter> {
80
78
  <meta name="msapplication-TileColor" content={this.app.identity.maincolor} />
81
79
  <meta name="apple-mobile-web-app-capable" content="yes" />
82
80
  <meta name="mobile-web-app-capable" content="yes" />
83
- <meta
84
- name="viewport"
85
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
86
- />
87
81
 
88
82
  {/* https://stackoverflow.com/questions/48956465/favicon-standard-2019-svg-ico-png-and-dimensions */}
89
83
  {/*<link rel="manifest" href={RES['manifest.json']} />*/}
90
- <link rel="shortcut icon" href="/public/app/favicon.ico" />
91
- <link rel="icon" type="image/png" sizes="16x16" href="/public/app/favicon-16x16.png" />
92
- <link rel="icon" type="image/png" sizes="32x32" href="/public/app/favicon-32x32.png" />
93
- <link rel="apple-touch-icon" sizes="180x180" href="/public/app/apple-touch-icon-180x180.png" />
94
- <meta name="msapplication-config" content="/public/app/browserconfig.xml" />
84
+ <link rel="shortcut icon" href={this.publicAssetUrl('app/favicon.ico', true)} />
85
+ <link
86
+ rel="icon"
87
+ type="image/png"
88
+ sizes="16x16"
89
+ href={this.publicAssetUrl('app/favicon-16x16.png', true)}
90
+ />
91
+ <link
92
+ rel="icon"
93
+ type="image/png"
94
+ sizes="32x32"
95
+ href={this.publicAssetUrl('app/favicon-32x32.png', true)}
96
+ />
97
+ <link
98
+ rel="apple-touch-icon"
99
+ sizes="180x180"
100
+ href={this.publicAssetUrl('app/apple-touch-icon-180x180.png', true)}
101
+ />
102
+ <meta name="msapplication-config" content={this.publicAssetUrl('app/browserconfig.xml', true)} />
95
103
 
96
104
  {/* Page */}
97
105
  <title>{page.title}</title>
@@ -165,7 +173,7 @@ export default class DocumentRenderer<TRouter extends TServerRouter> {
165
173
  return (
166
174
  <>
167
175
  {scripts.map((script) => {
168
- const src = this.clientAssetUrl(script, true);
176
+ const src = this.clientAssetUrl(script);
169
177
 
170
178
  return (
171
179
  <React.Fragment key={script}>
@@ -248,6 +256,10 @@ export default class DocumentRenderer<TRouter extends TServerRouter> {
248
256
  }
249
257
 
250
258
  private clientAssetUrl(asset: string, withBuildId = false) {
259
+ return this.publicAssetUrl(asset, withBuildId);
260
+ }
261
+
262
+ private publicAssetUrl(asset: string, withBuildId = false) {
251
263
  return `/public/${asset}${withBuildId ? `?v=${BUILD_ID}` : ''}`;
252
264
  }
253
265
  }