@tramvai/module-page-render-mode 2.70.0 → 2.72.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.
@@ -0,0 +1,39 @@
1
+ import { LAYOUT_OPTIONS, TRAMVAI_RENDER_MODE } from '@tramvai/tokens-render';
2
+ import { pageRenderHOC } from './PageRenderWrapper.es.js';
3
+ import { PAGE_RENDER_WRAPPER_TYPE, PAGE_RENDER_FALLBACK_COMPONENT_PREFIX, PAGE_RENDER_DEFAULT_MODE } from './tokens.es.js';
4
+
5
+ const sharedProviders = [
6
+ {
7
+ provide: LAYOUT_OPTIONS,
8
+ multi: true,
9
+ useFactory: ({ wrapperType }) => {
10
+ return {
11
+ wrappers: {
12
+ [wrapperType]: pageRenderHOC,
13
+ },
14
+ };
15
+ },
16
+ deps: {
17
+ wrapperType: PAGE_RENDER_WRAPPER_TYPE,
18
+ },
19
+ },
20
+ {
21
+ provide: PAGE_RENDER_FALLBACK_COMPONENT_PREFIX,
22
+ useValue: 'pageRenderFallback',
23
+ },
24
+ {
25
+ provide: PAGE_RENDER_DEFAULT_MODE,
26
+ useFactory: ({ tramvaiRenderMode }) => {
27
+ return tramvaiRenderMode;
28
+ },
29
+ deps: {
30
+ tramvaiRenderMode: TRAMVAI_RENDER_MODE,
31
+ },
32
+ },
33
+ {
34
+ provide: PAGE_RENDER_WRAPPER_TYPE,
35
+ useValue: 'page',
36
+ },
37
+ ];
38
+
39
+ export { sharedProviders };
package/lib/shared.js ADDED
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tokensRender = require('@tramvai/tokens-render');
6
+ var PageRenderWrapper = require('./PageRenderWrapper.js');
7
+ var tokens = require('./tokens.js');
8
+
9
+ const sharedProviders = [
10
+ {
11
+ provide: tokensRender.LAYOUT_OPTIONS,
12
+ multi: true,
13
+ useFactory: ({ wrapperType }) => {
14
+ return {
15
+ wrappers: {
16
+ [wrapperType]: PageRenderWrapper.pageRenderHOC,
17
+ },
18
+ };
19
+ },
20
+ deps: {
21
+ wrapperType: tokens.PAGE_RENDER_WRAPPER_TYPE,
22
+ },
23
+ },
24
+ {
25
+ provide: tokens.PAGE_RENDER_FALLBACK_COMPONENT_PREFIX,
26
+ useValue: 'pageRenderFallback',
27
+ },
28
+ {
29
+ provide: tokens.PAGE_RENDER_DEFAULT_MODE,
30
+ useFactory: ({ tramvaiRenderMode }) => {
31
+ return tramvaiRenderMode;
32
+ },
33
+ deps: {
34
+ tramvaiRenderMode: tokensRender.TRAMVAI_RENDER_MODE,
35
+ },
36
+ },
37
+ {
38
+ provide: tokens.PAGE_RENDER_WRAPPER_TYPE,
39
+ useValue: 'page',
40
+ },
41
+ ];
42
+
43
+ exports.sharedProviders = sharedProviders;
@@ -0,0 +1,73 @@
1
+ import fetch from 'node-fetch';
2
+ import { format } from '@tinkoff/url';
3
+
4
+ const userAgentByDeviceType = {
5
+ /** Chrome on Mobile */
6
+ 'mobile-modern': 'Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.3071.125 Mobile Safari/537.36',
7
+ /** Old Chrome on Mobile */
8
+ 'mobile-default': 'Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.3071.125 Mobile Safari/537.36',
9
+ /** Chrome on Mac OS */
10
+ 'desktop-modern': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.3987.87 Safari/537.36',
11
+ /** Old Chrome on Mac OS */
12
+ 'desktop-default': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.3987.87 Safari/537.36',
13
+ };
14
+ class BackgroundFetchService {
15
+ constructor({ logger, backgroundFetchEnabled, }) {
16
+ this.requests = new Set();
17
+ this.log = logger('static-pages');
18
+ this.backgroundFetchEnabled = backgroundFetchEnabled;
19
+ }
20
+ enabled() {
21
+ return this.backgroundFetchEnabled();
22
+ }
23
+ async revalidate({ key, path, port, deviceType, modern, }) {
24
+ if (this.requests.has(key)) {
25
+ return;
26
+ }
27
+ const revalidateUrl = format({
28
+ hostname: 'localhost',
29
+ port,
30
+ path,
31
+ });
32
+ this.requests.add(key);
33
+ this.log.debug({
34
+ event: 'background-fetch-init',
35
+ key,
36
+ revalidateUrl,
37
+ });
38
+ return fetch(revalidateUrl, {
39
+ headers: {
40
+ 'User-Agent': userAgentByDeviceType[`${deviceType}-${modern}`],
41
+ 'X-Tramvai-Static-Page-Revalidate': 'true',
42
+ },
43
+ timeout: 10000,
44
+ })
45
+ .then(async (response) => {
46
+ const body = await response.text();
47
+ const headers = response.headers.raw();
48
+ const { status } = response;
49
+ this.log.debug({
50
+ event: status >= 500 ? 'background-fetch-5xx' : 'background-fetch-success',
51
+ status,
52
+ key,
53
+ });
54
+ return {
55
+ body,
56
+ headers,
57
+ status,
58
+ };
59
+ })
60
+ .catch((error) => {
61
+ this.log.warn({
62
+ event: 'background-fetch-error',
63
+ error,
64
+ key,
65
+ });
66
+ })
67
+ .finally(() => {
68
+ this.requests.delete(key);
69
+ });
70
+ }
71
+ }
72
+
73
+ export { BackgroundFetchService };
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var fetch = require('node-fetch');
6
+ var url = require('@tinkoff/url');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
11
+
12
+ const userAgentByDeviceType = {
13
+ /** Chrome on Mobile */
14
+ 'mobile-modern': 'Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.3071.125 Mobile Safari/537.36',
15
+ /** Old Chrome on Mobile */
16
+ 'mobile-default': 'Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.3071.125 Mobile Safari/537.36',
17
+ /** Chrome on Mac OS */
18
+ 'desktop-modern': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.3987.87 Safari/537.36',
19
+ /** Old Chrome on Mac OS */
20
+ 'desktop-default': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.3987.87 Safari/537.36',
21
+ };
22
+ class BackgroundFetchService {
23
+ constructor({ logger, backgroundFetchEnabled, }) {
24
+ this.requests = new Set();
25
+ this.log = logger('static-pages');
26
+ this.backgroundFetchEnabled = backgroundFetchEnabled;
27
+ }
28
+ enabled() {
29
+ return this.backgroundFetchEnabled();
30
+ }
31
+ async revalidate({ key, path, port, deviceType, modern, }) {
32
+ if (this.requests.has(key)) {
33
+ return;
34
+ }
35
+ const revalidateUrl = url.format({
36
+ hostname: 'localhost',
37
+ port,
38
+ path,
39
+ });
40
+ this.requests.add(key);
41
+ this.log.debug({
42
+ event: 'background-fetch-init',
43
+ key,
44
+ revalidateUrl,
45
+ });
46
+ return fetch__default["default"](revalidateUrl, {
47
+ headers: {
48
+ 'User-Agent': userAgentByDeviceType[`${deviceType}-${modern}`],
49
+ 'X-Tramvai-Static-Page-Revalidate': 'true',
50
+ },
51
+ timeout: 10000,
52
+ })
53
+ .then(async (response) => {
54
+ const body = await response.text();
55
+ const headers = response.headers.raw();
56
+ const { status } = response;
57
+ this.log.debug({
58
+ event: status >= 500 ? 'background-fetch-5xx' : 'background-fetch-success',
59
+ status,
60
+ key,
61
+ });
62
+ return {
63
+ body,
64
+ headers,
65
+ status,
66
+ };
67
+ })
68
+ .catch((error) => {
69
+ this.log.warn({
70
+ event: 'background-fetch-error',
71
+ error,
72
+ key,
73
+ });
74
+ })
75
+ .finally(() => {
76
+ this.requests.delete(key);
77
+ });
78
+ }
79
+ }
80
+
81
+ exports.BackgroundFetchService = BackgroundFetchService;
@@ -0,0 +1,109 @@
1
+ class StaticPagesService {
2
+ constructor({ getCacheKey, requestManager, response, responseManager, environmentManager, userAgent, modern, logger, cache, modifyCache, shouldUseCache, shouldSetToCache, backgroundFetchService, options, cache5xxResponse, }) {
3
+ this.key = getCacheKey();
4
+ this.path = requestManager.getParsedUrl().pathname;
5
+ this.port = environmentManager.get('PORT');
6
+ this.deviceType = userAgent.mobileOS ? 'mobile' : 'desktop';
7
+ this.modern = modern ? 'modern' : 'default';
8
+ this.log = logger('static-pages');
9
+ this.responseManager = responseManager;
10
+ this.response = response;
11
+ this.cache = cache;
12
+ this.modifyCache = modifyCache;
13
+ this.shouldUseCache = shouldUseCache;
14
+ this.shouldSetToCache = shouldSetToCache;
15
+ this.backgroundFetchService = backgroundFetchService;
16
+ this.options = options;
17
+ this.cache5xxResponse = cache5xxResponse;
18
+ }
19
+ respond(onSuccess) {
20
+ if (!this.hasCache()) {
21
+ return;
22
+ }
23
+ const { ttl } = this.options;
24
+ let cacheEntry = this.getCache();
25
+ if (Array.isArray(this.modifyCache)) {
26
+ cacheEntry = this.modifyCache.reduce((result, modifier) => {
27
+ return modifier(result);
28
+ }, cacheEntry);
29
+ }
30
+ const { updatedAt, status, headers, body } = cacheEntry;
31
+ const isOutdated = updatedAt + ttl <= Date.now();
32
+ if (!isOutdated) {
33
+ this.log.debug({
34
+ event: 'cache-hit',
35
+ key: this.key,
36
+ });
37
+ this.response
38
+ .header('content-type', 'text/html')
39
+ .header('X-Tramvai-Static-Page-From-Cache', 'true')
40
+ .headers(headers)
41
+ .status(status)
42
+ .send(body);
43
+ onSuccess();
44
+ }
45
+ else {
46
+ this.log.debug({
47
+ event: 'cache-outdated',
48
+ key: this.key,
49
+ });
50
+ }
51
+ }
52
+ saveResponse() {
53
+ if (!this.cache5xxResponse() && this.responseManager.getStatus() >= 500) {
54
+ this.log.debug({
55
+ event: 'cache-set-5xx',
56
+ key: this.key,
57
+ });
58
+ return;
59
+ }
60
+ this.log.debug({
61
+ event: 'cache-set',
62
+ key: this.key,
63
+ });
64
+ this.setCache({
65
+ status: this.responseManager.getStatus(),
66
+ headers: this.responseManager.getHeaders(),
67
+ body: this.responseManager.getBody(),
68
+ });
69
+ }
70
+ async revalidate() {
71
+ if (!this.backgroundFetchService.enabled()) {
72
+ return;
73
+ }
74
+ await this.backgroundFetchService
75
+ .revalidate({
76
+ key: this.key,
77
+ path: this.path,
78
+ port: this.port,
79
+ deviceType: this.deviceType,
80
+ modern: this.modern,
81
+ })
82
+ .then((response) => {
83
+ if (!response) {
84
+ return;
85
+ }
86
+ if (!this.cache5xxResponse() && response.status >= 500) {
87
+ return;
88
+ }
89
+ this.setCache(response);
90
+ });
91
+ }
92
+ hasCache() {
93
+ return this.cache.has(this.path) && this.cache.get(this.path).has(this.key);
94
+ }
95
+ getCache() {
96
+ return this.cache.get(this.path).get(this.key);
97
+ }
98
+ setCache(cacheEntry) {
99
+ if (!this.cache.has(this.path)) {
100
+ this.cache.set(this.path, new Map());
101
+ }
102
+ this.cache.get(this.path).set(this.key, {
103
+ ...cacheEntry,
104
+ updatedAt: Date.now(),
105
+ });
106
+ }
107
+ }
108
+
109
+ export { StaticPagesService };
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ class StaticPagesService {
6
+ constructor({ getCacheKey, requestManager, response, responseManager, environmentManager, userAgent, modern, logger, cache, modifyCache, shouldUseCache, shouldSetToCache, backgroundFetchService, options, cache5xxResponse, }) {
7
+ this.key = getCacheKey();
8
+ this.path = requestManager.getParsedUrl().pathname;
9
+ this.port = environmentManager.get('PORT');
10
+ this.deviceType = userAgent.mobileOS ? 'mobile' : 'desktop';
11
+ this.modern = modern ? 'modern' : 'default';
12
+ this.log = logger('static-pages');
13
+ this.responseManager = responseManager;
14
+ this.response = response;
15
+ this.cache = cache;
16
+ this.modifyCache = modifyCache;
17
+ this.shouldUseCache = shouldUseCache;
18
+ this.shouldSetToCache = shouldSetToCache;
19
+ this.backgroundFetchService = backgroundFetchService;
20
+ this.options = options;
21
+ this.cache5xxResponse = cache5xxResponse;
22
+ }
23
+ respond(onSuccess) {
24
+ if (!this.hasCache()) {
25
+ return;
26
+ }
27
+ const { ttl } = this.options;
28
+ let cacheEntry = this.getCache();
29
+ if (Array.isArray(this.modifyCache)) {
30
+ cacheEntry = this.modifyCache.reduce((result, modifier) => {
31
+ return modifier(result);
32
+ }, cacheEntry);
33
+ }
34
+ const { updatedAt, status, headers, body } = cacheEntry;
35
+ const isOutdated = updatedAt + ttl <= Date.now();
36
+ if (!isOutdated) {
37
+ this.log.debug({
38
+ event: 'cache-hit',
39
+ key: this.key,
40
+ });
41
+ this.response
42
+ .header('content-type', 'text/html')
43
+ .header('X-Tramvai-Static-Page-From-Cache', 'true')
44
+ .headers(headers)
45
+ .status(status)
46
+ .send(body);
47
+ onSuccess();
48
+ }
49
+ else {
50
+ this.log.debug({
51
+ event: 'cache-outdated',
52
+ key: this.key,
53
+ });
54
+ }
55
+ }
56
+ saveResponse() {
57
+ if (!this.cache5xxResponse() && this.responseManager.getStatus() >= 500) {
58
+ this.log.debug({
59
+ event: 'cache-set-5xx',
60
+ key: this.key,
61
+ });
62
+ return;
63
+ }
64
+ this.log.debug({
65
+ event: 'cache-set',
66
+ key: this.key,
67
+ });
68
+ this.setCache({
69
+ status: this.responseManager.getStatus(),
70
+ headers: this.responseManager.getHeaders(),
71
+ body: this.responseManager.getBody(),
72
+ });
73
+ }
74
+ async revalidate() {
75
+ if (!this.backgroundFetchService.enabled()) {
76
+ return;
77
+ }
78
+ await this.backgroundFetchService
79
+ .revalidate({
80
+ key: this.key,
81
+ path: this.path,
82
+ port: this.port,
83
+ deviceType: this.deviceType,
84
+ modern: this.modern,
85
+ })
86
+ .then((response) => {
87
+ if (!response) {
88
+ return;
89
+ }
90
+ if (!this.cache5xxResponse() && response.status >= 500) {
91
+ return;
92
+ }
93
+ this.setCache(response);
94
+ });
95
+ }
96
+ hasCache() {
97
+ return this.cache.has(this.path) && this.cache.get(this.path).has(this.key);
98
+ }
99
+ getCache() {
100
+ return this.cache.get(this.path).get(this.key);
101
+ }
102
+ setCache(cacheEntry) {
103
+ if (!this.cache.has(this.path)) {
104
+ this.cache.set(this.path, new Map());
105
+ }
106
+ this.cache.get(this.path).set(this.key, {
107
+ ...cacheEntry,
108
+ updatedAt: Date.now(),
109
+ });
110
+ }
111
+ }
112
+
113
+ exports.StaticPagesService = StaticPagesService;
@@ -0,0 +1,226 @@
1
+ import isEmpty from '@tinkoff/utils/is/empty';
2
+ import { createToken, provide, Scope, commandLineListTokens, DI_TOKEN } from '@tramvai/core';
3
+ import { CREATE_CACHE_TOKEN, REQUEST_MANAGER_TOKEN, LOGGER_TOKEN, RESPONSE_MANAGER_TOKEN, ENV_MANAGER_TOKEN } from '@tramvai/tokens-common';
4
+ import { FASTIFY_RESPONSE } from '@tramvai/tokens-server-private';
5
+ import { MODERN_SATISFIES_TOKEN } from '@tramvai/tokens-render';
6
+ import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
7
+ import { USER_AGENT_TOKEN } from '@tramvai/module-client-hints';
8
+ import { SERVER_MODULE_PAPI_PRIVATE_ROUTE } from '@tramvai/tokens-server';
9
+ import { METRICS_MODULE_TOKEN } from '@tramvai/tokens-metrics';
10
+ import { createPapiMethod } from '@tramvai/papi';
11
+ import { StopCommandLineRunnerError } from './error.es.js';
12
+ import { STATIC_PAGES_CACHE_TOKEN, STATIC_PAGES_OPTIONS_TOKEN, STATIC_PAGES_SHOULD_SET_TO_CACHE, STATIC_PAGES_SHOULD_USE_CACHE, STATIC_PAGES_BACKGROUND_FETCH_ENABLED, STATIC_PAGES_CACHE_5xx_RESPONSE, STATIC_PAGES_MODIFY_CACHE, STATIC_PAGES_COMMAND_LINE, PAGE_RENDER_DEFAULT_MODE } from './tokens.es.js';
13
+ import { getPageRenderMode } from './utils/getPageRenderMode.es.js';
14
+ import { getCacheKey } from './utils/cacheKey.es.js';
15
+ import { BackgroundFetchService } from './staticPages/backgroundFetchService.es.js';
16
+ import { StaticPagesService } from './staticPages/staticPagesService.es.js';
17
+
18
+ const STATIC_PAGES_BACKGROUND_FETCH_SERVICE = createToken();
19
+ const STATIC_PAGES_GET_CACHE_KEY_TOKEN = createToken();
20
+ const STATIC_PAGES_CACHE_HIT_METRIC_TOKEN = createToken();
21
+ const STATIC_PAGES_SERVICE = createToken();
22
+ const staticPagesProviders = [
23
+ provide({
24
+ provide: STATIC_PAGES_CACHE_HIT_METRIC_TOKEN,
25
+ scope: Scope.SINGLETON,
26
+ useFactory: ({ metrics }) => {
27
+ return metrics.counter({
28
+ name: 'static_pages_cache_hit',
29
+ help: 'Total static pages returned from cache',
30
+ labelNames: [],
31
+ });
32
+ },
33
+ deps: {
34
+ metrics: METRICS_MODULE_TOKEN,
35
+ },
36
+ }),
37
+ provide({
38
+ provide: STATIC_PAGES_CACHE_TOKEN,
39
+ scope: Scope.SINGLETON,
40
+ useFactory: ({ createCache, staticPagesOptions }) => {
41
+ return createCache('memory', {
42
+ max: staticPagesOptions.maxSize,
43
+ });
44
+ },
45
+ deps: {
46
+ createCache: CREATE_CACHE_TOKEN,
47
+ staticPagesOptions: STATIC_PAGES_OPTIONS_TOKEN,
48
+ },
49
+ }),
50
+ provide({
51
+ provide: STATIC_PAGES_OPTIONS_TOKEN,
52
+ useValue: {
53
+ // @TODO: свой ttl для отдельных страниц
54
+ ttl: 60 * 1000,
55
+ maxSize: 1000,
56
+ },
57
+ }),
58
+ provide({
59
+ provide: STATIC_PAGES_GET_CACHE_KEY_TOKEN,
60
+ useFactory: ({ requestManager, userAgent, modern }) => {
61
+ return () => {
62
+ const deviceType = userAgent.mobileOS ? 'mobile' : 'desktop';
63
+ return getCacheKey({
64
+ method: requestManager.getMethod(),
65
+ host: requestManager.getHost(),
66
+ path: requestManager.getParsedUrl().pathname,
67
+ deviceType,
68
+ modern,
69
+ });
70
+ };
71
+ },
72
+ deps: {
73
+ requestManager: REQUEST_MANAGER_TOKEN,
74
+ userAgent: USER_AGENT_TOKEN,
75
+ modern: MODERN_SATISFIES_TOKEN,
76
+ },
77
+ }),
78
+ provide({
79
+ provide: STATIC_PAGES_SHOULD_SET_TO_CACHE,
80
+ useFactory: ({ requestManager }) => {
81
+ return () => {
82
+ return isEmpty(requestManager.getCookies());
83
+ };
84
+ },
85
+ deps: {
86
+ requestManager: REQUEST_MANAGER_TOKEN,
87
+ },
88
+ }),
89
+ provide({
90
+ provide: STATIC_PAGES_SHOULD_USE_CACHE,
91
+ useFactory: ({ requestManager }) => {
92
+ return () => {
93
+ return !requestManager.getHeader('x-tramvai-static-page-revalidate');
94
+ };
95
+ },
96
+ deps: {
97
+ requestManager: REQUEST_MANAGER_TOKEN,
98
+ },
99
+ }),
100
+ provide({
101
+ provide: STATIC_PAGES_BACKGROUND_FETCH_ENABLED,
102
+ useValue: () => {
103
+ return true;
104
+ },
105
+ }),
106
+ provide({
107
+ provide: STATIC_PAGES_CACHE_5xx_RESPONSE,
108
+ useValue: () => {
109
+ return false;
110
+ },
111
+ }),
112
+ provide({
113
+ provide: STATIC_PAGES_BACKGROUND_FETCH_SERVICE,
114
+ scope: Scope.REQUEST,
115
+ useClass: BackgroundFetchService,
116
+ deps: {
117
+ logger: LOGGER_TOKEN,
118
+ backgroundFetchEnabled: STATIC_PAGES_BACKGROUND_FETCH_ENABLED,
119
+ },
120
+ }),
121
+ provide({
122
+ provide: STATIC_PAGES_SERVICE,
123
+ scope: Scope.REQUEST,
124
+ useClass: StaticPagesService,
125
+ deps: {
126
+ getCacheKey: STATIC_PAGES_GET_CACHE_KEY_TOKEN,
127
+ requestManager: REQUEST_MANAGER_TOKEN,
128
+ responseManager: RESPONSE_MANAGER_TOKEN,
129
+ response: FASTIFY_RESPONSE,
130
+ environmentManager: ENV_MANAGER_TOKEN,
131
+ userAgent: USER_AGENT_TOKEN,
132
+ modern: MODERN_SATISFIES_TOKEN,
133
+ logger: LOGGER_TOKEN,
134
+ cache: STATIC_PAGES_CACHE_TOKEN,
135
+ modifyCache: { token: STATIC_PAGES_MODIFY_CACHE, optional: true },
136
+ shouldUseCache: STATIC_PAGES_SHOULD_USE_CACHE,
137
+ shouldSetToCache: STATIC_PAGES_SHOULD_SET_TO_CACHE,
138
+ backgroundFetchService: STATIC_PAGES_BACKGROUND_FETCH_SERVICE,
139
+ options: STATIC_PAGES_OPTIONS_TOKEN,
140
+ cache5xxResponse: STATIC_PAGES_CACHE_5xx_RESPONSE,
141
+ },
142
+ }),
143
+ provide({
144
+ provide: commandLineListTokens.init,
145
+ multi: true,
146
+ scope: Scope.SINGLETON,
147
+ useFactory: ({ di, staticPagesCommandLine }) => {
148
+ return function registerResponseCacheHandler() {
149
+ di.register({
150
+ provide: staticPagesCommandLine
151
+ ? commandLineListTokens[staticPagesCommandLine]
152
+ : commandLineListTokens.customerStart,
153
+ useFactory: ({ staticPagesService, staticPagesCacheHitMetric, logger }) => {
154
+ logger('static-pages');
155
+ return function staticPagesFromCache() {
156
+ if (staticPagesService.shouldUseCache()) {
157
+ staticPagesService.respond(() => {
158
+ // @TODO: маска урла на этом этапе?
159
+ staticPagesCacheHitMetric.inc();
160
+ throw new StopCommandLineRunnerError();
161
+ });
162
+ }
163
+ };
164
+ },
165
+ deps: {
166
+ staticPagesService: STATIC_PAGES_SERVICE,
167
+ staticPagesCacheHitMetric: STATIC_PAGES_CACHE_HIT_METRIC_TOKEN,
168
+ logger: LOGGER_TOKEN,
169
+ },
170
+ });
171
+ };
172
+ },
173
+ deps: {
174
+ di: DI_TOKEN,
175
+ staticPagesCommandLine: { token: STATIC_PAGES_COMMAND_LINE, optional: true },
176
+ },
177
+ }),
178
+ provide({
179
+ provide: commandLineListTokens.clear,
180
+ useFactory: ({ staticPagesService, pageService, defaultRenderMode }) => {
181
+ return function cacheStaticPages() {
182
+ const isStaticPage = getPageRenderMode({ pageService, defaultRenderMode }) === 'static';
183
+ if (!isStaticPage) {
184
+ return;
185
+ }
186
+ if (staticPagesService.shouldSetToCache()) {
187
+ staticPagesService.saveResponse();
188
+ }
189
+ else {
190
+ staticPagesService.revalidate();
191
+ }
192
+ };
193
+ },
194
+ deps: {
195
+ staticPagesService: STATIC_PAGES_SERVICE,
196
+ pageService: PAGE_SERVICE_TOKEN,
197
+ defaultRenderMode: PAGE_RENDER_DEFAULT_MODE,
198
+ },
199
+ }),
200
+ provide({
201
+ provide: SERVER_MODULE_PAPI_PRIVATE_ROUTE,
202
+ useFactory: ({ staticPagesCache }) => {
203
+ return createPapiMethod({
204
+ path: '/revalidate/',
205
+ method: 'post',
206
+ async handler({ body = {} }) {
207
+ const { path } = body;
208
+ const pathKey = `/${path}/`;
209
+ if (!path) {
210
+ staticPagesCache.clear();
211
+ }
212
+ else if (staticPagesCache.has(pathKey)) {
213
+ staticPagesCache.set(pathKey, new Map());
214
+ // @TODO: revalidate request with background fetch?
215
+ }
216
+ return 'Success';
217
+ },
218
+ });
219
+ },
220
+ deps: {
221
+ staticPagesCache: STATIC_PAGES_CACHE_TOKEN,
222
+ },
223
+ }),
224
+ ];
225
+
226
+ export { STATIC_PAGES_BACKGROUND_FETCH_SERVICE, STATIC_PAGES_CACHE_HIT_METRIC_TOKEN, STATIC_PAGES_GET_CACHE_KEY_TOKEN, STATIC_PAGES_SERVICE, staticPagesProviders };