@tramvai/module-page-render-mode 7.11.0 → 7.16.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/lib/browser.js CHANGED
@@ -6,7 +6,7 @@ import { sharedProviders } from './shared.browser.js';
6
6
  import { STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE } from './private-tokens.browser.js';
7
7
  import { getPageRenderMode } from './utils/getPageRenderMode.browser.js';
8
8
  import { PAGE_RENDER_DEFAULT_MODE } from './tokens.browser.js';
9
- export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE } from './tokens.browser.js';
9
+ export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_ROUTE_TREE, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE } from './tokens.browser.js';
10
10
 
11
11
  // @todo: перенести в @tramvai/module-render
12
12
  const PageRenderModeModule = declareModule({
@@ -1,5 +1,6 @@
1
1
  import type { Counter, Gauge } from 'prom-client';
2
2
  import { TramvaiRenderMode } from '@tramvai/tokens-render';
3
+ import { Route } from '@tinkoff/router';
3
4
  import { BackgroundFetchService } from './staticPages/backgroundFetchService';
4
5
  import { FileSystemCache } from './staticPages/fileSystemCache';
5
6
  export declare const STATIC_PAGES_BACKGROUND_FETCH_SERVICE: BackgroundFetchService & {
@@ -21,7 +22,7 @@ export declare const STATIC_PAGES_FS_CACHE_METRICS_TOKEN: {
21
22
  } & {
22
23
  __type?: "base token" | undefined;
23
24
  };
24
- export declare const STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE: (() => TramvaiRenderMode) & {
25
+ export declare const STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE: ((route?: Route) => TramvaiRenderMode) & {
25
26
  __type?: "base token" | undefined;
26
27
  };
27
28
  //# sourceMappingURL=private-tokens.d.ts.map
package/lib/server.es.js CHANGED
@@ -2,7 +2,7 @@ import { declareModule } from '@tramvai/core';
2
2
  import { ForceCSRModule } from './ForceCSRModule.es.js';
3
3
  import { sharedProviders } from './shared.es.js';
4
4
  import { staticPagesProviders } from './staticPages.es.js';
5
- export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE } from './tokens.es.js';
5
+ export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_ROUTE_TREE, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE } from './tokens.es.js';
6
6
 
7
7
  // @todo: перенести в @tramvai/module-render
8
8
  const PageRenderModeModule = declareModule({
package/lib/server.js CHANGED
@@ -29,6 +29,7 @@ exports.STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN = tokens.STATIC_PAGES_FS_CACHE_OPTIO
29
29
  exports.STATIC_PAGES_KEY_TOKEN = tokens.STATIC_PAGES_KEY_TOKEN;
30
30
  exports.STATIC_PAGES_MODIFY_CACHE = tokens.STATIC_PAGES_MODIFY_CACHE;
31
31
  exports.STATIC_PAGES_OPTIONS_TOKEN = tokens.STATIC_PAGES_OPTIONS_TOKEN;
32
+ exports.STATIC_PAGES_ROUTE_TREE = tokens.STATIC_PAGES_ROUTE_TREE;
32
33
  exports.STATIC_PAGES_SERVICE = tokens.STATIC_PAGES_SERVICE;
33
34
  exports.STATIC_PAGES_SHOULD_USE_CACHE = tokens.STATIC_PAGES_SHOULD_USE_CACHE;
34
35
  exports.PageRenderModeModule = PageRenderModeModule;
@@ -15,10 +15,11 @@ export declare class BackgroundFetchService {
15
15
  backgroundFetchEnabled: BackgroundCacheEnabled;
16
16
  });
17
17
  enabled(): boolean;
18
- revalidate({ cacheKey, pathname, headers, }: {
18
+ revalidate({ cacheKey, pathname, headers, query, }: {
19
19
  cacheKey: string;
20
20
  pathname: string;
21
21
  headers: Record<string, string | string[] | undefined>;
22
+ query?: Record<string, string | string[]>;
22
23
  }): Promise<void | {
23
24
  body: string;
24
25
  headers: {
@@ -15,14 +15,16 @@ class BackgroundFetchService {
15
15
  enabled() {
16
16
  return this.backgroundFetchEnabled();
17
17
  }
18
- async revalidate({ cacheKey, pathname, headers, }) {
18
+ async revalidate({ cacheKey, pathname, headers, query, }) {
19
19
  if (this.requests.has(cacheKey)) {
20
20
  return;
21
21
  }
22
+ // TODO: support --https
22
23
  const revalidateUrl = format({
23
24
  hostname: this.hostname,
24
25
  port: this.port,
25
26
  path: pathname,
27
+ query,
26
28
  });
27
29
  this.requests.add(cacheKey);
28
30
  this.log.debug({
@@ -34,6 +36,7 @@ class BackgroundFetchService {
34
36
  headers: {
35
37
  ...headers,
36
38
  'X-Tramvai-Static-Page-Revalidate': 'true',
39
+ 'X-Tramvai-Service-Name': 'BACKGROUND_STATIC_PAGE_REVALIDATE',
37
40
  },
38
41
  signal: AbortSignal.timeout(10000),
39
42
  // we need to save raw redirect response status code and headers
@@ -19,14 +19,16 @@ class BackgroundFetchService {
19
19
  enabled() {
20
20
  return this.backgroundFetchEnabled();
21
21
  }
22
- async revalidate({ cacheKey, pathname, headers, }) {
22
+ async revalidate({ cacheKey, pathname, headers, query, }) {
23
23
  if (this.requests.has(cacheKey)) {
24
24
  return;
25
25
  }
26
+ // TODO: support --https
26
27
  const revalidateUrl = url.format({
27
28
  hostname: this.hostname,
28
29
  port: this.port,
29
30
  path: pathname,
31
+ query,
30
32
  });
31
33
  this.requests.add(cacheKey);
32
34
  this.log.debug({
@@ -38,6 +40,7 @@ class BackgroundFetchService {
38
40
  headers: {
39
41
  ...headers,
40
42
  'X-Tramvai-Static-Page-Revalidate': 'true',
43
+ 'X-Tramvai-Service-Name': 'BACKGROUND_STATIC_PAGE_REVALIDATE',
41
44
  },
42
45
  signal: AbortSignal.timeout(10000),
43
46
  // we need to save raw redirect response status code and headers
@@ -18,7 +18,7 @@ class FileSystemCache {
18
18
  metrics;
19
19
  limit = pLimit(8);
20
20
  constructor({ directory, maxSize, ttl, allowStale, logger, metrics, }) {
21
- this.directory = directory;
21
+ this.directory = path.isAbsolute(directory) ? directory : path.join(process.cwd(), directory);
22
22
  this.maxSize = maxSize;
23
23
  this.ttl = ttl;
24
24
  this.allowStale = allowStale;
@@ -35,6 +35,8 @@ class FileSystemCache {
35
35
  directory: this.directory,
36
36
  });
37
37
  try {
38
+ // fill zero values for metrics
39
+ this.updateMetrics();
38
40
  await this.scanDirectory();
39
41
  this.log.info({
40
42
  event: 'init-complete',
@@ -44,11 +46,19 @@ class FileSystemCache {
44
46
  this.updateMetrics();
45
47
  }
46
48
  catch (error) {
47
- if (process.env.NODE_ENV === 'development' && error?.code === 'ENOENT') {
48
- // in development mode, static directory path includes unique build id and can be missing on first run, so just create it
49
- await promises.mkdir(this.directory, { recursive: true });
49
+ if (error?.code === 'ENOENT') {
50
+ // static directory path can be missing on first run, so always create it
51
+ await promises.mkdir(this.directory, { recursive: true }).catch((mkdirError) => {
52
+ this.log.warn({
53
+ event: 'mkdir-error',
54
+ message: `Failed to create static cache directory ${this.directory}, maybe read-only file system is used.
55
+ In k8s environment, it means that "readOnlyRootFilesystem" option is enabled for deployment, to fix this issue, add 'dist' directory as a emptyDir volume mount.`,
56
+ error: mkdirError,
57
+ });
58
+ });
50
59
  }
51
- else {
60
+ // static directory path includes unique build id in development mode, so warn only in production
61
+ if (process.env.NODE_ENV !== 'development') {
52
62
  this.log.warn({
53
63
  event: 'init-error',
54
64
  message: error?.code === 'ENOENT'
@@ -253,7 +263,7 @@ and copy "dist/static" folder into the Docker image, to ensure the pages cache i
253
263
  }
254
264
  catch (error) {
255
265
  if (process.env.NODE_ENV !== 'development') {
256
- this.log.warn({
266
+ this.log.info({
257
267
  event: 'meta-read-error',
258
268
  error: error,
259
269
  });
@@ -27,7 +27,7 @@ class FileSystemCache {
27
27
  metrics;
28
28
  limit = pLimit__default["default"](8);
29
29
  constructor({ directory, maxSize, ttl, allowStale, logger, metrics, }) {
30
- this.directory = directory;
30
+ this.directory = path__default["default"].isAbsolute(directory) ? directory : path__default["default"].join(process.cwd(), directory);
31
31
  this.maxSize = maxSize;
32
32
  this.ttl = ttl;
33
33
  this.allowStale = allowStale;
@@ -44,6 +44,8 @@ class FileSystemCache {
44
44
  directory: this.directory,
45
45
  });
46
46
  try {
47
+ // fill zero values for metrics
48
+ this.updateMetrics();
47
49
  await this.scanDirectory();
48
50
  this.log.info({
49
51
  event: 'init-complete',
@@ -53,11 +55,19 @@ class FileSystemCache {
53
55
  this.updateMetrics();
54
56
  }
55
57
  catch (error) {
56
- if (process.env.NODE_ENV === 'development' && error?.code === 'ENOENT') {
57
- // in development mode, static directory path includes unique build id and can be missing on first run, so just create it
58
- await node_fs.promises.mkdir(this.directory, { recursive: true });
58
+ if (error?.code === 'ENOENT') {
59
+ // static directory path can be missing on first run, so always create it
60
+ await node_fs.promises.mkdir(this.directory, { recursive: true }).catch((mkdirError) => {
61
+ this.log.warn({
62
+ event: 'mkdir-error',
63
+ message: `Failed to create static cache directory ${this.directory}, maybe read-only file system is used.
64
+ In k8s environment, it means that "readOnlyRootFilesystem" option is enabled for deployment, to fix this issue, add 'dist' directory as a emptyDir volume mount.`,
65
+ error: mkdirError,
66
+ });
67
+ });
59
68
  }
60
- else {
69
+ // static directory path includes unique build id in development mode, so warn only in production
70
+ if (process.env.NODE_ENV !== 'development') {
61
71
  this.log.warn({
62
72
  event: 'init-error',
63
73
  message: error?.code === 'ENOENT'
@@ -262,7 +272,7 @@ and copy "dist/static" folder into the Docker image, to ensure the pages cache i
262
272
  }
263
273
  catch (error) {
264
274
  if (process.env.NODE_ENV !== 'development') {
265
- this.log.warn({
275
+ this.log.info({
266
276
  event: 'meta-read-error',
267
277
  error: error,
268
278
  });
@@ -1,7 +1,17 @@
1
1
  import { getCacheKey } from '../utils/cacheKey.es.js';
2
2
 
3
3
  // `Location` is required for 3xx responses
4
- const DEFAULT_HEADERS_WHITELIST = ['Location', 'Content-Type', 'Content-Length', 'X-App-Id'];
4
+ // `X-Original-Host` and `Host` are required for RequestManager and Router
5
+ const DEFAULT_HEADERS_WHITELIST = [
6
+ 'Location',
7
+ 'Content-Type',
8
+ 'Content-Length',
9
+ 'X-App-Id',
10
+ 'X-Original-Host',
11
+ 'Host',
12
+ 'X-Forwarded-Host',
13
+ 'X-Forwarded-Proto',
14
+ ];
5
15
  class StaticPagesService {
6
16
  key;
7
17
  pathname;
@@ -39,6 +49,7 @@ class StaticPagesService {
39
49
  this.cache5xxResponse = cache5xxResponse;
40
50
  this.cacheControlFactory = cacheControlFactory;
41
51
  }
52
+ // eslint-disable-next-line max-statements
42
53
  async respond(onSuccess) {
43
54
  if (!this.hasCache()) {
44
55
  this.log.debug({
@@ -134,7 +145,9 @@ class StaticPagesService {
134
145
  }
135
146
  }
136
147
  const incomingHeaders = this.requestManager.getHeaders();
148
+ const incomingQuery = this.requestManager.getParsedUrl().query;
137
149
  const revalidateHeaders = {};
150
+ const revalidateQuery = {};
138
151
  this.options.allowedHeaders.concat(DEFAULT_HEADERS_WHITELIST).forEach((header) => {
139
152
  const lowercaseHeader = header.toLowerCase();
140
153
  if (incomingHeaders[header]) {
@@ -144,11 +157,17 @@ class StaticPagesService {
144
157
  revalidateHeaders[lowercaseHeader] = incomingHeaders[lowercaseHeader];
145
158
  }
146
159
  });
160
+ this.options.allowedQuery.forEach((query) => {
161
+ if (incomingQuery[query]) {
162
+ revalidateQuery[query] = incomingQuery[query];
163
+ }
164
+ });
147
165
  await this.backgroundFetchService
148
166
  .revalidate({
149
167
  cacheKey: this.cacheKey,
150
168
  pathname: this.pathname,
151
169
  headers: revalidateHeaders,
170
+ query: revalidateQuery,
152
171
  })
153
172
  .then((response) => {
154
173
  if (!response) {
@@ -161,6 +180,16 @@ class StaticPagesService {
161
180
  });
162
181
  return;
163
182
  }
183
+ // for 4xx responses we want to cache only HTML pages
184
+ if (response.status >= 400 &&
185
+ response.status < 500 &&
186
+ !response.headers['content-type']?.includes('text/html')) {
187
+ this.log.debug({
188
+ event: 'cache-set-4xx',
189
+ cacheKey: this.cacheKey,
190
+ });
191
+ return;
192
+ }
164
193
  const cachedHeaders = {};
165
194
  const responseHeaders = response.headers;
166
195
  this.options.allowedHeaders.concat(DEFAULT_HEADERS_WHITELIST).forEach((header) => {
@@ -5,7 +5,17 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var cacheKey = require('../utils/cacheKey.js');
6
6
 
7
7
  // `Location` is required for 3xx responses
8
- const DEFAULT_HEADERS_WHITELIST = ['Location', 'Content-Type', 'Content-Length', 'X-App-Id'];
8
+ // `X-Original-Host` and `Host` are required for RequestManager and Router
9
+ const DEFAULT_HEADERS_WHITELIST = [
10
+ 'Location',
11
+ 'Content-Type',
12
+ 'Content-Length',
13
+ 'X-App-Id',
14
+ 'X-Original-Host',
15
+ 'Host',
16
+ 'X-Forwarded-Host',
17
+ 'X-Forwarded-Proto',
18
+ ];
9
19
  class StaticPagesService {
10
20
  key;
11
21
  pathname;
@@ -43,6 +53,7 @@ class StaticPagesService {
43
53
  this.cache5xxResponse = cache5xxResponse;
44
54
  this.cacheControlFactory = cacheControlFactory;
45
55
  }
56
+ // eslint-disable-next-line max-statements
46
57
  async respond(onSuccess) {
47
58
  if (!this.hasCache()) {
48
59
  this.log.debug({
@@ -138,7 +149,9 @@ class StaticPagesService {
138
149
  }
139
150
  }
140
151
  const incomingHeaders = this.requestManager.getHeaders();
152
+ const incomingQuery = this.requestManager.getParsedUrl().query;
141
153
  const revalidateHeaders = {};
154
+ const revalidateQuery = {};
142
155
  this.options.allowedHeaders.concat(DEFAULT_HEADERS_WHITELIST).forEach((header) => {
143
156
  const lowercaseHeader = header.toLowerCase();
144
157
  if (incomingHeaders[header]) {
@@ -148,11 +161,17 @@ class StaticPagesService {
148
161
  revalidateHeaders[lowercaseHeader] = incomingHeaders[lowercaseHeader];
149
162
  }
150
163
  });
164
+ this.options.allowedQuery.forEach((query) => {
165
+ if (incomingQuery[query]) {
166
+ revalidateQuery[query] = incomingQuery[query];
167
+ }
168
+ });
151
169
  await this.backgroundFetchService
152
170
  .revalidate({
153
171
  cacheKey: this.cacheKey,
154
172
  pathname: this.pathname,
155
173
  headers: revalidateHeaders,
174
+ query: revalidateQuery,
156
175
  })
157
176
  .then((response) => {
158
177
  if (!response) {
@@ -165,6 +184,16 @@ class StaticPagesService {
165
184
  });
166
185
  return;
167
186
  }
187
+ // for 4xx responses we want to cache only HTML pages
188
+ if (response.status >= 400 &&
189
+ response.status < 500 &&
190
+ !response.headers['content-type']?.includes('text/html')) {
191
+ this.log.debug({
192
+ event: 'cache-set-4xx',
193
+ cacheKey: this.cacheKey,
194
+ });
195
+ return;
196
+ }
168
197
  const cachedHeaders = {};
169
198
  const responseHeaders = response.headers;
170
199
  this.options.allowedHeaders.concat(DEFAULT_HEADERS_WHITELIST).forEach((header) => {
@@ -1,8 +1,15 @@
1
1
  /// <reference types="node" />
2
+ import { Route, RouteTree } from '@tinkoff/router';
2
3
  import { BackgroundFetchService } from './staticPages/backgroundFetchService';
3
4
  import { StaticPagesService } from './staticPages/staticPagesService';
4
5
  import { FileSystemCache } from './staticPages/fileSystemCache';
5
- export declare const staticPagesProviders: (import("@tinkoff/dippy/lib/Provider").ValueProvider<{
6
+ export declare const staticPagesProviders: (import("@tinkoff/dippy/lib/Provider").ValueProvider<((route?: Route | undefined) => import("@tramvai/tokens-render").TramvaiRenderMode) & {
7
+ __type?: "base token" | undefined;
8
+ }> | import("@tinkoff/dippy/lib/Provider").ClassProviderWithoutDeps<((route?: Route | undefined) => import("@tramvai/tokens-render").TramvaiRenderMode) & {
9
+ __type?: "base token" | undefined;
10
+ }> | import("@tinkoff/dippy/lib/Provider").FactoryProviderWithoutDeps<((route?: Route | undefined) => import("@tramvai/tokens-render").TramvaiRenderMode) & {
11
+ __type?: "base token" | undefined;
12
+ }> | import("@tinkoff/dippy/lib/Provider").ValueProvider<{
6
13
  hit: import("prom-client").Counter<any>;
7
14
  } & {
8
15
  __type?: "base token" | undefined;
@@ -228,7 +235,7 @@ export declare const staticPagesProviders: (import("@tinkoff/dippy/lib/Provider"
228
235
  }) | null;
229
236
  optional: true;
230
237
  };
231
- }, (() => import("@tramvai/tokens-render").TramvaiRenderMode) & {
238
+ }, ((route?: Route | undefined) => import("@tramvai/tokens-render").TramvaiRenderMode) & {
232
239
  __type?: "base token" | undefined;
233
240
  }> | import("@tinkoff/dippy/lib/Provider").FactoryProviderWithDeps<{
234
241
  requestManager: import("@tramvai/tokens-common").RequestManager & {
@@ -261,7 +268,7 @@ export declare const staticPagesProviders: (import("@tinkoff/dippy/lib/Provider"
261
268
  }) | null;
262
269
  optional: true;
263
270
  };
264
- }, (() => import("@tramvai/tokens-render").TramvaiRenderMode) & {
271
+ }, ((route?: Route | undefined) => import("@tramvai/tokens-render").TramvaiRenderMode) & {
265
272
  __type?: "base token" | undefined;
266
273
  }> | import("@tinkoff/dippy/lib/Provider").ValueProvider<BackgroundFetchService & {
267
274
  __type?: "base token" | undefined;
@@ -531,5 +538,41 @@ export declare const staticPagesProviders: (import("@tinkoff/dippy/lib/Provider"
531
538
  __papi_parameters__: import("@tramvai/papi").NormalizedPapiParameters<any, any>;
532
539
  } & {
533
540
  __type?: "multi token" | undefined;
541
+ }> | import("@tinkoff/dippy/lib/Provider").ValueProvider<RouteTree & {
542
+ __type?: "base token" | undefined;
543
+ }> | import("@tinkoff/dippy/lib/Provider").ClassProviderWithDeps<{
544
+ di: import("@tinkoff/dippy").Container & {
545
+ __type?: "base token" | undefined;
546
+ };
547
+ }, RouteTree & {
548
+ __type?: "base token" | undefined;
549
+ }> | import("@tinkoff/dippy/lib/Provider").ClassProviderWithoutDeps<RouteTree & {
550
+ __type?: "base token" | undefined;
551
+ }> | import("@tinkoff/dippy/lib/Provider").FactoryProviderWithDeps<{
552
+ di: import("@tinkoff/dippy").Container & {
553
+ __type?: "base token" | undefined;
554
+ };
555
+ }, RouteTree & {
556
+ __type?: "base token" | undefined;
557
+ }> | import("@tinkoff/dippy/lib/Provider").FactoryProviderWithoutDeps<RouteTree & {
558
+ __type?: "base token" | undefined;
559
+ }> | import("@tinkoff/dippy/lib/Provider").ClassProviderWithDeps<{
560
+ router: import("@tinkoff/router").AbstractRouter & {
561
+ __type?: "base token" | undefined;
562
+ };
563
+ routeTree: RouteTree & {
564
+ __type?: "base token" | undefined;
565
+ };
566
+ }, import("@tramvai/core").Command & {
567
+ __type?: "multi token" | undefined;
568
+ }> | import("@tinkoff/dippy/lib/Provider").FactoryProviderWithDeps<{
569
+ router: import("@tinkoff/router").AbstractRouter & {
570
+ __type?: "base token" | undefined;
571
+ };
572
+ routeTree: RouteTree & {
573
+ __type?: "base token" | undefined;
574
+ };
575
+ }, import("@tramvai/core").Command & {
576
+ __type?: "multi token" | undefined;
534
577
  }>)[];
535
578
  //# sourceMappingURL=staticPages.d.ts.map
@@ -1,12 +1,14 @@
1
+ import flatten from '@tinkoff/utils/array/flatten';
1
2
  import { provide, Scope, commandLineListTokens, optional, DI_TOKEN } from '@tramvai/core';
2
3
  import { CREATE_CACHE_TOKEN, LOGGER_TOKEN, REQUEST_MANAGER_TOKEN, ENV_MANAGER_TOKEN, RESPONSE_MANAGER_TOKEN } from '@tramvai/tokens-common';
3
4
  import { FASTIFY_RESPONSE } from '@tramvai/tokens-server-private';
4
- import { ROUTER_TOKEN, PAGE_SERVICE_TOKEN, LINK_PREFETCH_MANAGER_TOKEN, PAGE_REGISTRY_TOKEN } from '@tramvai/tokens-router';
5
+ import { ROUTER_TOKEN, PAGE_SERVICE_TOKEN, LINK_PREFETCH_MANAGER_TOKEN, PAGE_REGISTRY_TOKEN, ROUTES_TOKEN } from '@tramvai/tokens-router';
5
6
  import { SERVER_MODULE_PAPI_PRIVATE_ROUTE } from '@tramvai/tokens-server';
6
7
  import { METRICS_MODULE_TOKEN } from '@tramvai/tokens-metrics';
7
8
  import { createPapiMethod } from '@tramvai/papi';
9
+ import { isWildcard, RouteTree } from '@tinkoff/router';
8
10
  import { StopCommandLineRunnerError } from './error.es.js';
9
- import { STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_SHOULD_USE_CACHE, PAGE_RENDER_DEFAULT_MODE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_SERVICE, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_COMMAND_LINE } from './tokens.es.js';
11
+ import { STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_SHOULD_USE_CACHE, PAGE_RENDER_DEFAULT_MODE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_SERVICE, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_ROUTE_TREE, STATIC_PAGES_COMMAND_LINE } from './tokens.es.js';
10
12
  import { getPageRenderMode } from './utils/getPageRenderMode.es.js';
11
13
  import { getCacheKey } from './utils/cacheKey.es.js';
12
14
  import { BackgroundFetchService } from './staticPages/backgroundFetchService.es.js';
@@ -14,6 +16,11 @@ import { StaticPagesService } from './staticPages/staticPagesService.es.js';
14
16
  import { FileSystemCache } from './staticPages/fileSystemCache.es.js';
15
17
  import { STATIC_PAGES_CACHE_METRICS_TOKEN, STATIC_PAGES_FS_CACHE_METRICS_TOKEN, STATIC_PAGES_FS_CACHE_TOKEN, STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE, STATIC_PAGES_BACKGROUND_FETCH_SERVICE } from './private-tokens.es.js';
16
18
 
19
+ // small performance optimization to prevent stack trace generation for static StopCommandLineRunnerError
20
+ const { stackTraceLimit } = Error;
21
+ Error.stackTraceLimit = 0;
22
+ const STOP_COMMAND_LINE_ERROR = new StopCommandLineRunnerError();
23
+ Error.stackTraceLimit = stackTraceLimit;
17
24
  const staticPagesProviders = [
18
25
  provide({
19
26
  provide: STATIC_PAGES_CACHE_METRICS_TOKEN,
@@ -48,11 +55,14 @@ const staticPagesProviders = [
48
55
  provide({
49
56
  provide: STATIC_PAGES_OPTIONS_TOKEN,
50
57
  useValue: {
51
- // @TODO: unique ttl per pages
58
+ // @TODO: unique cache parameters per pages
52
59
  ttl: 5 * 60 * 1000,
53
60
  maxSize: 100,
54
61
  allowStale: true,
62
+ // @TODO: unique headers per pages
55
63
  allowedHeaders: [],
64
+ // @TODO: unique query per pages
65
+ allowedQuery: [],
56
66
  },
57
67
  }),
58
68
  provide({
@@ -170,9 +180,10 @@ const staticPagesProviders = [
170
180
  provide({
171
181
  provide: STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE,
172
182
  useFactory: ({ requestManager, pageService, router, defaultRenderMode, fileSystemCache }) => {
173
- return () => getPageRenderMode({
183
+ return (route) => getPageRenderMode({
174
184
  pageService,
175
185
  router,
186
+ route,
176
187
  requestManager,
177
188
  defaultRenderMode,
178
189
  fileSystemCache,
@@ -240,12 +251,13 @@ const staticPagesProviders = [
240
251
  provide: staticPagesCommandLine
241
252
  ? commandLineListTokens[staticPagesCommandLine]
242
253
  : commandLineListTokens.customerStart,
243
- useFactory: ({ staticPagesService, staticPagesCacheMetrics, logger, requestManager, responseManager, staticPagesKey, linkPrefetchManager, resolvePageRenderMode, router, pageRegistry, }) => {
254
+ useFactory: ({ staticPagesService, staticPagesCacheMetrics, logger, requestManager, responseManager, staticPagesKey, linkPrefetchManager, resolvePageRenderMode, router, pageRegistry, routeTree, }) => {
244
255
  const log = logger('static-pages');
256
+ // eslint-disable-next-line max-statements
245
257
  return async function staticPagesFromCache() {
246
258
  const isPrerenderRequest = !!requestManager.getHeader('x-tramvai-prerender');
247
259
  const { pathname } = requestManager.getParsedUrl();
248
- const route = router?.getCurrentRoute() ?? router?.resolve(pathname);
260
+ let route = router?.getCurrentRoute() ?? router?.resolve(pathname);
249
261
  // prefetch route only for `tramvai static` because it can be async and slow in runtime
250
262
  if (isPrerenderRequest) {
251
263
  log.debug(`Should prefetch route and component to determine if page is static: ${pathname}`);
@@ -260,8 +272,22 @@ const staticPagesProviders = [
260
272
  }
261
273
  });
262
274
  }
263
- const isStatic = resolvePageRenderMode() === 'static';
275
+ // dynamic route will be resolved after prefetch
276
+ if (isPrerenderRequest && !route) {
277
+ route = router?.getCurrentRoute() ?? router?.resolve(pathname);
278
+ }
279
+ const isStatic = resolvePageRenderMode(route) === 'static';
264
280
  const shouldUseCache = staticPagesService.shouldUseCache();
281
+ // we can't use cache for wildcard routes,
282
+ // because wildcard routes can match any possible urls
283
+ const isWildcardRoute = route
284
+ ? isWildcard(route.path)
285
+ : routeTree.getWildcard(pathname);
286
+ // routes can be resolved in runtime with ROUTE_RESOLVE_TOKEN,
287
+ // but this routes exists only in Request scope, so we use STATIC_PAGES_ROUTE_TREE
288
+ // to save minimal info about resolved routes between requests, because
289
+ // we want to be sure that we use cache and revalidation only for resolved routes
290
+ const isUnknownRoute = !route && !routeTree.getRoute(pathname);
265
291
  if (isStatic) {
266
292
  responseManager.setHeader('X-Tramvai-Static-Page-Key', staticPagesKey());
267
293
  // we need to tell for `tramvai static` prerendering command that this page has `static` render mode,
@@ -270,16 +296,23 @@ const staticPagesProviders = [
270
296
  if (isPrerenderRequest && route) {
271
297
  responseManager.setHeader('X-Tramvai-Static-Page-Route', JSON.stringify(route));
272
298
  }
273
- if (shouldUseCache) {
274
- log.debug(`Should use static pages cache: ${pathname}`);
299
+ if (shouldUseCache && !isWildcardRoute && !isUnknownRoute) {
300
+ log.info(`Should use static pages cache: ${pathname}`);
275
301
  await staticPagesService.respond(() => {
276
- log.debug(`Successful static page response from cache: ${pathname}`);
302
+ log.info(`Successful static page response from cache: ${pathname}`);
277
303
  staticPagesCacheMetrics.hit.inc();
278
- throw new StopCommandLineRunnerError();
304
+ throw STOP_COMMAND_LINE_ERROR;
279
305
  });
280
306
  }
281
307
  else {
282
- log.debug(`Static pages cache is not used for this request: ${pathname}`);
308
+ let msg = `Static pages cache is not used for this request: ${pathname}`;
309
+ if (shouldUseCache && isWildcardRoute) {
310
+ msg += `, because wildcard route was resolved`;
311
+ }
312
+ else if (shouldUseCache && isUnknownRoute) {
313
+ msg += `, because route for this url was never resolved`;
314
+ }
315
+ log.info(msg);
283
316
  }
284
317
  }
285
318
  };
@@ -295,6 +328,7 @@ const staticPagesProviders = [
295
328
  resolvePageRenderMode: STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE,
296
329
  router: optional(ROUTER_TOKEN),
297
330
  pageRegistry: optional(PAGE_REGISTRY_TOKEN),
331
+ routeTree: STATIC_PAGES_ROUTE_TREE,
298
332
  },
299
333
  });
300
334
  };
@@ -367,6 +401,37 @@ const staticPagesProviders = [
367
401
  logger: LOGGER_TOKEN,
368
402
  },
369
403
  }),
404
+ provide({
405
+ provide: STATIC_PAGES_ROUTE_TREE,
406
+ scope: Scope.SINGLETON,
407
+ useFactory: ({ di }) => {
408
+ const staticRoutes = di.get(optional(ROUTES_TOKEN)) ?? [];
409
+ return new RouteTree(flatten(staticRoutes).map((route) => ({ name: route.name, path: route.path })));
410
+ },
411
+ deps: {
412
+ di: DI_TOKEN,
413
+ },
414
+ }),
415
+ provide({
416
+ provide: commandLineListTokens.clear,
417
+ useFactory: ({ router, routeTree }) => {
418
+ return () => {
419
+ const currentUrl = router.getCurrentUrl();
420
+ const currentRoute = router.getCurrentRoute();
421
+ // save dynamically resolved route in route tree to use it in next requests before route resolving
422
+ if (currentRoute && currentUrl && !routeTree.getRoute(currentUrl.pathname)) {
423
+ routeTree.addRoute({
424
+ name: currentRoute.name,
425
+ path: currentRoute.path,
426
+ });
427
+ }
428
+ };
429
+ },
430
+ deps: {
431
+ router: ROUTER_TOKEN,
432
+ routeTree: STATIC_PAGES_ROUTE_TREE,
433
+ },
434
+ }),
370
435
  ];
371
436
 
372
437
  export { staticPagesProviders };
@@ -2,6 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var flatten = require('@tinkoff/utils/array/flatten');
5
6
  var core = require('@tramvai/core');
6
7
  var tokensCommon = require('@tramvai/tokens-common');
7
8
  var tokensServerPrivate = require('@tramvai/tokens-server-private');
@@ -9,6 +10,7 @@ var tokensRouter = require('@tramvai/tokens-router');
9
10
  var tokensServer = require('@tramvai/tokens-server');
10
11
  var tokensMetrics = require('@tramvai/tokens-metrics');
11
12
  var papi = require('@tramvai/papi');
13
+ var router = require('@tinkoff/router');
12
14
  var error = require('./error.js');
13
15
  var tokens = require('./tokens.js');
14
16
  var getPageRenderMode = require('./utils/getPageRenderMode.js');
@@ -18,6 +20,15 @@ var staticPagesService = require('./staticPages/staticPagesService.js');
18
20
  var fileSystemCache = require('./staticPages/fileSystemCache.js');
19
21
  var privateTokens = require('./private-tokens.js');
20
22
 
23
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
24
+
25
+ var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
26
+
27
+ // small performance optimization to prevent stack trace generation for static StopCommandLineRunnerError
28
+ const { stackTraceLimit } = Error;
29
+ Error.stackTraceLimit = 0;
30
+ const STOP_COMMAND_LINE_ERROR = new error.StopCommandLineRunnerError();
31
+ Error.stackTraceLimit = stackTraceLimit;
21
32
  const staticPagesProviders = [
22
33
  core.provide({
23
34
  provide: privateTokens.STATIC_PAGES_CACHE_METRICS_TOKEN,
@@ -52,11 +63,14 @@ const staticPagesProviders = [
52
63
  core.provide({
53
64
  provide: tokens.STATIC_PAGES_OPTIONS_TOKEN,
54
65
  useValue: {
55
- // @TODO: unique ttl per pages
66
+ // @TODO: unique cache parameters per pages
56
67
  ttl: 5 * 60 * 1000,
57
68
  maxSize: 100,
58
69
  allowStale: true,
70
+ // @TODO: unique headers per pages
59
71
  allowedHeaders: [],
72
+ // @TODO: unique query per pages
73
+ allowedQuery: [],
60
74
  },
61
75
  }),
62
76
  core.provide({
@@ -174,9 +188,10 @@ const staticPagesProviders = [
174
188
  core.provide({
175
189
  provide: privateTokens.STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE,
176
190
  useFactory: ({ requestManager, pageService, router, defaultRenderMode, fileSystemCache }) => {
177
- return () => getPageRenderMode.getPageRenderMode({
191
+ return (route) => getPageRenderMode.getPageRenderMode({
178
192
  pageService,
179
193
  router,
194
+ route,
180
195
  requestManager,
181
196
  defaultRenderMode,
182
197
  fileSystemCache,
@@ -244,12 +259,13 @@ const staticPagesProviders = [
244
259
  provide: staticPagesCommandLine
245
260
  ? core.commandLineListTokens[staticPagesCommandLine]
246
261
  : core.commandLineListTokens.customerStart,
247
- useFactory: ({ staticPagesService, staticPagesCacheMetrics, logger, requestManager, responseManager, staticPagesKey, linkPrefetchManager, resolvePageRenderMode, router, pageRegistry, }) => {
262
+ useFactory: ({ staticPagesService, staticPagesCacheMetrics, logger, requestManager, responseManager, staticPagesKey, linkPrefetchManager, resolvePageRenderMode, router: router$1, pageRegistry, routeTree, }) => {
248
263
  const log = logger('static-pages');
264
+ // eslint-disable-next-line max-statements
249
265
  return async function staticPagesFromCache() {
250
266
  const isPrerenderRequest = !!requestManager.getHeader('x-tramvai-prerender');
251
267
  const { pathname } = requestManager.getParsedUrl();
252
- const route = router?.getCurrentRoute() ?? router?.resolve(pathname);
268
+ let route = router$1?.getCurrentRoute() ?? router$1?.resolve(pathname);
253
269
  // prefetch route only for `tramvai static` because it can be async and slow in runtime
254
270
  if (isPrerenderRequest) {
255
271
  log.debug(`Should prefetch route and component to determine if page is static: ${pathname}`);
@@ -264,8 +280,22 @@ const staticPagesProviders = [
264
280
  }
265
281
  });
266
282
  }
267
- const isStatic = resolvePageRenderMode() === 'static';
283
+ // dynamic route will be resolved after prefetch
284
+ if (isPrerenderRequest && !route) {
285
+ route = router$1?.getCurrentRoute() ?? router$1?.resolve(pathname);
286
+ }
287
+ const isStatic = resolvePageRenderMode(route) === 'static';
268
288
  const shouldUseCache = staticPagesService.shouldUseCache();
289
+ // we can't use cache for wildcard routes,
290
+ // because wildcard routes can match any possible urls
291
+ const isWildcardRoute = route
292
+ ? router.isWildcard(route.path)
293
+ : routeTree.getWildcard(pathname);
294
+ // routes can be resolved in runtime with ROUTE_RESOLVE_TOKEN,
295
+ // but this routes exists only in Request scope, so we use STATIC_PAGES_ROUTE_TREE
296
+ // to save minimal info about resolved routes between requests, because
297
+ // we want to be sure that we use cache and revalidation only for resolved routes
298
+ const isUnknownRoute = !route && !routeTree.getRoute(pathname);
269
299
  if (isStatic) {
270
300
  responseManager.setHeader('X-Tramvai-Static-Page-Key', staticPagesKey());
271
301
  // we need to tell for `tramvai static` prerendering command that this page has `static` render mode,
@@ -274,16 +304,23 @@ const staticPagesProviders = [
274
304
  if (isPrerenderRequest && route) {
275
305
  responseManager.setHeader('X-Tramvai-Static-Page-Route', JSON.stringify(route));
276
306
  }
277
- if (shouldUseCache) {
278
- log.debug(`Should use static pages cache: ${pathname}`);
307
+ if (shouldUseCache && !isWildcardRoute && !isUnknownRoute) {
308
+ log.info(`Should use static pages cache: ${pathname}`);
279
309
  await staticPagesService.respond(() => {
280
- log.debug(`Successful static page response from cache: ${pathname}`);
310
+ log.info(`Successful static page response from cache: ${pathname}`);
281
311
  staticPagesCacheMetrics.hit.inc();
282
- throw new error.StopCommandLineRunnerError();
312
+ throw STOP_COMMAND_LINE_ERROR;
283
313
  });
284
314
  }
285
315
  else {
286
- log.debug(`Static pages cache is not used for this request: ${pathname}`);
316
+ let msg = `Static pages cache is not used for this request: ${pathname}`;
317
+ if (shouldUseCache && isWildcardRoute) {
318
+ msg += `, because wildcard route was resolved`;
319
+ }
320
+ else if (shouldUseCache && isUnknownRoute) {
321
+ msg += `, because route for this url was never resolved`;
322
+ }
323
+ log.info(msg);
287
324
  }
288
325
  }
289
326
  };
@@ -299,6 +336,7 @@ const staticPagesProviders = [
299
336
  resolvePageRenderMode: privateTokens.STATIC_PAGES_RESOLVE_PAGE_RENDER_MODE,
300
337
  router: core.optional(tokensRouter.ROUTER_TOKEN),
301
338
  pageRegistry: core.optional(tokensRouter.PAGE_REGISTRY_TOKEN),
339
+ routeTree: tokens.STATIC_PAGES_ROUTE_TREE,
302
340
  },
303
341
  });
304
342
  };
@@ -371,6 +409,37 @@ const staticPagesProviders = [
371
409
  logger: tokensCommon.LOGGER_TOKEN,
372
410
  },
373
411
  }),
412
+ core.provide({
413
+ provide: tokens.STATIC_PAGES_ROUTE_TREE,
414
+ scope: core.Scope.SINGLETON,
415
+ useFactory: ({ di }) => {
416
+ const staticRoutes = di.get(core.optional(tokensRouter.ROUTES_TOKEN)) ?? [];
417
+ return new router.RouteTree(flatten__default["default"](staticRoutes).map((route) => ({ name: route.name, path: route.path })));
418
+ },
419
+ deps: {
420
+ di: core.DI_TOKEN,
421
+ },
422
+ }),
423
+ core.provide({
424
+ provide: core.commandLineListTokens.clear,
425
+ useFactory: ({ router, routeTree }) => {
426
+ return () => {
427
+ const currentUrl = router.getCurrentUrl();
428
+ const currentRoute = router.getCurrentRoute();
429
+ // save dynamically resolved route in route tree to use it in next requests before route resolving
430
+ if (currentRoute && currentUrl && !routeTree.getRoute(currentUrl.pathname)) {
431
+ routeTree.addRoute({
432
+ name: currentRoute.name,
433
+ path: currentRoute.path,
434
+ });
435
+ }
436
+ };
437
+ },
438
+ deps: {
439
+ router: tokensRouter.ROUTER_TOKEN,
440
+ routeTree: tokens.STATIC_PAGES_ROUTE_TREE,
441
+ },
442
+ }),
374
443
  ];
375
444
 
376
445
  exports.staticPagesProviders = staticPagesProviders;
@@ -28,5 +28,8 @@ const STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN = createToken('static pages cache-
28
28
  scope: Scope.REQUEST,
29
29
  });
30
30
  const STATIC_PAGES_SERVICE = createToken('static pages service');
31
+ const STATIC_PAGES_ROUTE_TREE = createToken('static pages route tree', {
32
+ scope: Scope.SINGLETON,
33
+ });
31
34
 
32
- export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE };
35
+ export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_ROUTE_TREE, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE };
package/lib/tokens.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { TramvaiRenderMode } from '@tramvai/tokens-render';
2
2
  import type { Cache, ResponseManager } from '@tramvai/tokens-common';
3
+ import { RouteTree } from '@tinkoff/router';
3
4
  import { StaticPagesService } from './staticPages/staticPagesService';
4
5
  export declare const PAGE_RENDER_FALLBACK_COMPONENT_PREFIX: string & {
5
6
  __type?: "base token" | undefined;
@@ -53,10 +54,18 @@ export interface StaticPagesOptions {
53
54
  allowStale: boolean;
54
55
  /**
55
56
  * Whitelist of headers, that are allowed to be passed from client request to backround cache revalidation request,
56
- * and allowed to be cached and returned with the cached response
57
+ * and allowed to be cached and returned with the cached response.
58
+ * Some headers are required and can't be removed from this list:
59
+ * ['Location', 'Content-Type', 'Content-Length', 'X-App-Id', 'X-Original-Host', 'Host', 'X-Forwarded-Host', 'X-Forwarded-Proto']
57
60
  * @default []
58
61
  */
59
62
  allowedHeaders: string[];
63
+ /**
64
+ * Whitelist of query parameters, that are allowed to be passed from client request to backround cache revalidation request,
65
+ * and allowed to be cached and returned with the cached response
66
+ * @default []
67
+ */
68
+ allowedQuery: string[];
60
69
  }
61
70
  export declare const STATIC_PAGES_CACHE_TOKEN: Cache<StaticPagesCacheEntry> & {
62
71
  __type?: "base token" | undefined;
@@ -142,4 +151,7 @@ export declare const STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN: ((entry: {
142
151
  export declare const STATIC_PAGES_SERVICE: StaticPagesService & {
143
152
  __type?: "base token" | undefined;
144
153
  };
154
+ export declare const STATIC_PAGES_ROUTE_TREE: RouteTree & {
155
+ __type?: "base token" | undefined;
156
+ };
145
157
  //# sourceMappingURL=tokens.d.ts.map
package/lib/tokens.es.js CHANGED
@@ -28,5 +28,8 @@ const STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN = createToken('static pages cache-
28
28
  scope: Scope.REQUEST,
29
29
  });
30
30
  const STATIC_PAGES_SERVICE = createToken('static pages service');
31
+ const STATIC_PAGES_ROUTE_TREE = createToken('static pages route tree', {
32
+ scope: Scope.SINGLETON,
33
+ });
31
34
 
32
- export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE };
35
+ export { PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT, PAGE_RENDER_DEFAULT_MODE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_WRAPPER_TYPE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN, STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_COMMAND_LINE, STATIC_PAGES_FS_CACHE_ENABLED, STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN, STATIC_PAGES_KEY_TOKEN, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_ROUTE_TREE, STATIC_PAGES_SERVICE, STATIC_PAGES_SHOULD_USE_CACHE };
package/lib/tokens.js CHANGED
@@ -32,6 +32,9 @@ const STATIC_PAGES_CACHE_CONTROL_HEADER_TOKEN = dippy.createToken('static pages
32
32
  scope: dippy.Scope.REQUEST,
33
33
  });
34
34
  const STATIC_PAGES_SERVICE = dippy.createToken('static pages service');
35
+ const STATIC_PAGES_ROUTE_TREE = dippy.createToken('static pages route tree', {
36
+ scope: dippy.Scope.SINGLETON,
37
+ });
35
38
 
36
39
  exports.PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT = PAGE_RENDER_DEFAULT_FALLBACK_COMPONENT;
37
40
  exports.PAGE_RENDER_DEFAULT_MODE = PAGE_RENDER_DEFAULT_MODE;
@@ -47,5 +50,6 @@ exports.STATIC_PAGES_FS_CACHE_OPTIONS_TOKEN = STATIC_PAGES_FS_CACHE_OPTIONS_TOKE
47
50
  exports.STATIC_PAGES_KEY_TOKEN = STATIC_PAGES_KEY_TOKEN;
48
51
  exports.STATIC_PAGES_MODIFY_CACHE = STATIC_PAGES_MODIFY_CACHE;
49
52
  exports.STATIC_PAGES_OPTIONS_TOKEN = STATIC_PAGES_OPTIONS_TOKEN;
53
+ exports.STATIC_PAGES_ROUTE_TREE = STATIC_PAGES_ROUTE_TREE;
50
54
  exports.STATIC_PAGES_SERVICE = STATIC_PAGES_SERVICE;
51
55
  exports.STATIC_PAGES_SHOULD_USE_CACHE = STATIC_PAGES_SHOULD_USE_CACHE;
@@ -1,5 +1,5 @@
1
- const getPageRenderMode = ({ requestManager, router, pageService, defaultRenderMode, fileSystemCache, }) => {
2
- const resolvedRoute = router?.getCurrentRoute() ?? router?.resolve(requestManager.getParsedUrl().pathname);
1
+ const getPageRenderMode = ({ requestManager, router, route, pageService, defaultRenderMode, fileSystemCache, }) => {
2
+ const resolvedRoute = route ?? router?.getCurrentRoute() ?? router?.resolve(requestManager.getParsedUrl().pathname);
3
3
  // if we can't resolve route, it means that we are on 404 page, or has dynamic routing,
4
4
  // so we can't determine render mode by page config or page component property, and should fallback to default render mode
5
5
  if (!resolvedRoute) {
@@ -2,11 +2,13 @@ import type { ExtractDependencyType } from '@tinkoff/dippy';
2
2
  import type { TramvaiRenderMode } from '@tramvai/tokens-render';
3
3
  import type { PAGE_SERVICE_TOKEN, ROUTER_TOKEN } from '@tramvai/tokens-router';
4
4
  import { REQUEST_MANAGER_TOKEN } from '@tramvai/tokens-common';
5
+ import { Route } from '@tinkoff/router';
5
6
  import type { PAGE_RENDER_DEFAULT_MODE } from '../tokens';
6
7
  import { STATIC_PAGES_FS_CACHE_TOKEN } from '../private-tokens';
7
- export declare const getPageRenderMode: ({ requestManager, router, pageService, defaultRenderMode, fileSystemCache, }: {
8
+ export declare const getPageRenderMode: ({ requestManager, router, route, pageService, defaultRenderMode, fileSystemCache, }: {
8
9
  requestManager: ExtractDependencyType<typeof REQUEST_MANAGER_TOKEN>;
9
10
  router: ExtractDependencyType<typeof ROUTER_TOKEN> | null;
11
+ route?: Route | undefined;
10
12
  pageService: ExtractDependencyType<typeof PAGE_SERVICE_TOKEN> | null;
11
13
  defaultRenderMode: ExtractDependencyType<typeof PAGE_RENDER_DEFAULT_MODE>;
12
14
  fileSystemCache?: import("../staticPages/fileSystemCache").FileSystemCache | null | undefined;
@@ -1,5 +1,5 @@
1
- const getPageRenderMode = ({ requestManager, router, pageService, defaultRenderMode, fileSystemCache, }) => {
2
- const resolvedRoute = router?.getCurrentRoute() ?? router?.resolve(requestManager.getParsedUrl().pathname);
1
+ const getPageRenderMode = ({ requestManager, router, route, pageService, defaultRenderMode, fileSystemCache, }) => {
2
+ const resolvedRoute = route ?? router?.getCurrentRoute() ?? router?.resolve(requestManager.getParsedUrl().pathname);
3
3
  // if we can't resolve route, it means that we are on 404 page, or has dynamic routing,
4
4
  // so we can't determine render mode by page config or page component property, and should fallback to default render mode
5
5
  if (!resolvedRoute) {
@@ -2,8 +2,8 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const getPageRenderMode = ({ requestManager, router, pageService, defaultRenderMode, fileSystemCache, }) => {
6
- const resolvedRoute = router?.getCurrentRoute() ?? router?.resolve(requestManager.getParsedUrl().pathname);
5
+ const getPageRenderMode = ({ requestManager, router, route, pageService, defaultRenderMode, fileSystemCache, }) => {
6
+ const resolvedRoute = route ?? router?.getCurrentRoute() ?? router?.resolve(requestManager.getParsedUrl().pathname);
7
7
  // if we can't resolve route, it means that we are on 404 page, or has dynamic routing,
8
8
  // so we can't determine render mode by page config or page component property, and should fallback to default render mode
9
9
  if (!resolvedRoute) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/module-page-render-mode",
3
- "version": "7.11.0",
3
+ "version": "7.16.0",
4
4
  "description": "Enable different rendering modes for pages",
5
5
  "main": "./lib/server.js",
6
6
  "module": "./lib/server.es.js",
@@ -28,21 +28,21 @@
28
28
  "p-limit": "^3"
29
29
  },
30
30
  "peerDependencies": {
31
- "@tinkoff/dippy": "0.13.2",
32
- "@tinkoff/router": "0.7.32",
31
+ "@tinkoff/dippy": "^1.0.0",
32
+ "@tinkoff/router": "0.7.55",
33
33
  "@tinkoff/utils": "^2.1.2",
34
- "@tramvai/core": "7.11.0",
35
- "@tramvai/module-client-hints": "7.11.0",
36
- "@tramvai/module-router": "7.11.0",
37
- "@tramvai/papi": "7.11.0",
38
- "@tramvai/react": "7.11.0",
39
- "@tramvai/tokens-common": "7.11.0",
40
- "@tramvai/tokens-core": "7.11.0",
41
- "@tramvai/tokens-metrics": "7.11.0",
42
- "@tramvai/tokens-render": "7.11.0",
43
- "@tramvai/tokens-router": "7.11.0",
44
- "@tramvai/tokens-server": "7.11.0",
45
- "@tramvai/tokens-server-private": "7.11.0",
34
+ "@tramvai/core": "7.16.0",
35
+ "@tramvai/module-client-hints": "7.16.0",
36
+ "@tramvai/module-router": "7.16.0",
37
+ "@tramvai/papi": "7.16.0",
38
+ "@tramvai/react": "7.16.0",
39
+ "@tramvai/tokens-common": "7.16.0",
40
+ "@tramvai/tokens-core": "7.16.0",
41
+ "@tramvai/tokens-metrics": "7.16.0",
42
+ "@tramvai/tokens-render": "7.16.0",
43
+ "@tramvai/tokens-router": "7.16.0",
44
+ "@tramvai/tokens-server": "7.16.0",
45
+ "@tramvai/tokens-server-private": "7.16.0",
46
46
  "prom-client": "^14.2.0",
47
47
  "react": ">=16.14.0",
48
48
  "tslib": "^2.4.0"