@zengenti/contensis-react-base 4.0.0-beta.6 → 4.0.0-beta.61
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 +14 -1
- package/cjs/{App-vZrUfVgQ.js → App-TTUKj85f.js} +498 -104
- package/cjs/App-TTUKj85f.js.map +1 -0
- package/cjs/{ChangePassword.container-ECjEXixF.js → ChangePassword.container-C4Du3Wb1.js} +57 -50
- package/cjs/ChangePassword.container-C4Du3Wb1.js.map +1 -0
- package/cjs/{SSRContext-DVj_QAC1.js → ContensisDeliveryApi-gN3_MHEl.js} +32 -74
- package/cjs/ContensisDeliveryApi-gN3_MHEl.js.map +1 -0
- package/cjs/CookieConstants-DfPiWCRZ.js +12 -0
- package/cjs/CookieConstants-DfPiWCRZ.js.map +1 -0
- package/{esm/CookieHelper.class-FTURFpz3.js → cjs/CookieHelper.class-Det3qfdU.js} +4 -6
- package/cjs/CookieHelper.class-Det3qfdU.js.map +1 -0
- package/cjs/{RouteLoader-D5Yg7EB5.js → RouteLoader-BM8DyfcF.js} +17 -9
- package/cjs/RouteLoader-BM8DyfcF.js.map +1 -0
- package/cjs/SSRContext-DotLlTQc.js +116 -0
- package/cjs/SSRContext-DotLlTQc.js.map +1 -0
- package/cjs/ToJs-BsWqWjdm.js +23 -0
- package/cjs/ToJs-BsWqWjdm.js.map +1 -0
- package/cjs/{VersionInfo-B_dKCubg.js → VersionInfo-zFPsvS8q.js} +3 -25
- package/cjs/VersionInfo-zFPsvS8q.js.map +1 -0
- package/cjs/client.js +62 -64
- package/cjs/client.js.map +1 -1
- package/cjs/contensis-react-base.js +246 -135
- package/cjs/contensis-react-base.js.map +1 -1
- package/cjs/i18n.js +75 -0
- package/cjs/i18n.js.map +1 -0
- package/cjs/{ToJs-C9jwV7YB.js → matchGroups-dqONU-vY.js} +2 -22
- package/cjs/matchGroups-dqONU-vY.js.map +1 -0
- package/cjs/redux.js +8 -6
- package/cjs/redux.js.map +1 -1
- package/cjs/routing.js +15 -7
- package/cjs/routing.js.map +1 -1
- package/cjs/{sagas-CbZhaRNd.js → sagas-OfBUtx74.js} +523 -370
- package/cjs/sagas-OfBUtx74.js.map +1 -0
- package/cjs/search.js +54 -29
- package/cjs/search.js.map +1 -1
- package/cjs/{selectors-wCs5fHD4.js → selectors-BrxJ8-F8.js} +27 -6
- package/cjs/selectors-BrxJ8-F8.js.map +1 -0
- package/cjs/selectors-DAQR0uZa.js +18 -0
- package/cjs/selectors-DAQR0uZa.js.map +1 -0
- package/cjs/slice-5xJMH24n.js +69 -0
- package/cjs/slice-5xJMH24n.js.map +1 -0
- package/cjs/{store-D07FOXvM.js → store-Dn7vP6G0.js} +52 -4
- package/cjs/store-Dn7vP6G0.js.map +1 -0
- package/cjs/urls-DGZlAs0y.js +25 -0
- package/cjs/urls-DGZlAs0y.js.map +1 -0
- package/cjs/user.js +20 -17
- package/cjs/user.js.map +1 -1
- package/cjs/util-wQwG9vit.js +148 -0
- package/cjs/util-wQwG9vit.js.map +1 -0
- package/cjs/util.js +80 -22
- package/cjs/util.js.map +1 -1
- package/cjs/{version-B7XFkBhY.js → version-2FamXHhj.js} +15 -16
- package/cjs/version-2FamXHhj.js.map +1 -0
- package/cjs/{version-CM-bJ62L.js → version-rFG9Y6_B.js} +2 -2
- package/cjs/{version-CM-bJ62L.js.map → version-rFG9Y6_B.js.map} +1 -1
- package/esm/{App-DLZweVSp.js → App-DaHtrw85.js} +458 -65
- package/esm/App-DaHtrw85.js.map +1 -0
- package/esm/{ChangePassword.container-BgzIy8dA.js → ChangePassword.container-CUBtn82K.js} +19 -13
- package/esm/ChangePassword.container-CUBtn82K.js.map +1 -0
- package/esm/{SSRContext-BE8ElZ3X.js → ContensisDeliveryApi-CvEoOLCl.js} +30 -67
- package/esm/ContensisDeliveryApi-CvEoOLCl.js.map +1 -0
- package/esm/CookieConstants-DEmbwzYr.js +7 -0
- package/esm/CookieConstants-DEmbwzYr.js.map +1 -0
- package/{cjs/CookieHelper.class-C3Eqoze9.js → esm/CookieHelper.class-C6rTRl_1.js} +2 -14
- package/esm/CookieHelper.class-C6rTRl_1.js.map +1 -0
- package/esm/{RouteLoader-xeQBXywk.js → RouteLoader-BwDPahRW.js} +14 -6
- package/esm/RouteLoader-BwDPahRW.js.map +1 -0
- package/esm/SSRContext-CYxBWky3.js +106 -0
- package/esm/SSRContext-CYxBWky3.js.map +1 -0
- package/esm/ToJs-BnRRHk6f.js +17 -0
- package/esm/ToJs-BnRRHk6f.js.map +1 -0
- package/esm/{VersionInfo-Cno7K0OA.js → VersionInfo-By2ZCZOh.js} +4 -24
- package/esm/VersionInfo-By2ZCZOh.js.map +1 -0
- package/esm/client.js +62 -63
- package/esm/client.js.map +1 -1
- package/esm/contensis-react-base.js +239 -130
- package/esm/contensis-react-base.js.map +1 -1
- package/esm/i18n.js +64 -0
- package/esm/i18n.js.map +1 -0
- package/esm/{ToJs-CNzfvyxJ.js → matchGroups-_w8BwzCC.js} +3 -18
- package/esm/matchGroups-_w8BwzCC.js.map +1 -0
- package/esm/redux.js +11 -8
- package/esm/redux.js.map +1 -1
- package/esm/routing.js +14 -7
- package/esm/routing.js.map +1 -1
- package/esm/{sagas-xJU-zOpn.js → sagas-BZWjx5by.js} +511 -357
- package/esm/sagas-BZWjx5by.js.map +1 -0
- package/esm/search.js +73 -47
- package/esm/search.js.map +1 -1
- package/esm/{selectors-DO2ocdOp.js → selectors-8ROQrTd7.js} +25 -7
- package/esm/selectors-8ROQrTd7.js.map +1 -0
- package/esm/selectors-DcmvOeX2.js +10 -0
- package/esm/selectors-DcmvOeX2.js.map +1 -0
- package/esm/slice-C6JLQik8.js +63 -0
- package/esm/slice-C6JLQik8.js.map +1 -0
- package/esm/{store-3u0RzHZ0.js → store-DSjRYsM2.js} +52 -5
- package/esm/store-DSjRYsM2.js.map +1 -0
- package/esm/urls-tLxo_skx.js +22 -0
- package/esm/urls-tLxo_skx.js.map +1 -0
- package/esm/user.js +9 -6
- package/esm/user.js.map +1 -1
- package/esm/util-BafFLYzn.js +136 -0
- package/esm/util-BafFLYzn.js.map +1 -0
- package/esm/util.js +58 -14
- package/esm/util.js.map +1 -1
- package/esm/{version-BlsI7hX2.js → version-B75wA6Te.js} +16 -16
- package/esm/version-B75wA6Te.js.map +1 -0
- package/esm/{version-wnf-TITV.js → version-BQAL8sQO.js} +2 -2
- package/esm/{version-wnf-TITV.js.map → version-BQAL8sQO.js.map} +1 -1
- package/i18n/package.json +5 -0
- package/models/app/pages/VersionInfo/components/VersionInfo.d.ts +1 -1
- package/models/app/pages/VersionInfo/components/VersionInfo.styled.d.ts +0 -1
- package/models/i18n/index.d.ts +5 -0
- package/models/i18n/redux/sagas.d.ts +19 -0
- package/models/i18n/redux/selectors.d.ts +11 -0
- package/models/i18n/redux/slice.d.ts +198 -0
- package/models/i18n/routes.d.ts +8 -0
- package/models/i18n/useI18n.hook.d.ts +20 -0
- package/models/index.d.ts +1 -0
- package/models/models/AppState.d.ts +2 -0
- package/models/models/ContentTypeMapping.d.ts +5 -0
- package/models/models/Locales.d.ts +11 -0
- package/models/models/MatchedRoute.d.ts +5 -1
- package/models/models/RouteComponent.d.ts +0 -1
- package/models/models/SSRContext.d.ts +4 -4
- package/models/models/StaticRoute.d.ts +11 -0
- package/models/models/WithEvents.d.ts +8 -0
- package/models/models/config/AppConfig.d.ts +2 -0
- package/models/models/config/I18n.d.ts +38 -0
- package/models/models/config/ServerConfig.d.ts +14 -0
- package/models/redux/index.d.ts +2 -1
- package/models/redux/sagas/index.d.ts +3 -1
- package/models/redux/sagas/injector.d.ts +13 -0
- package/models/redux/store/injectors/index.d.ts +26 -0
- package/models/redux/store/injectors/inject.d.ts +24 -0
- package/models/redux/store/injectors/util.d.ts +2 -0
- package/models/redux/store/store.d.ts +13 -4
- package/models/redux/util.d.ts +1 -1
- package/models/routing/components/RouteLoader.d.ts +3 -3
- package/models/routing/httpContext.d.ts +0 -1
- package/models/routing/index.d.ts +1 -0
- package/models/routing/redux/actions.d.ts +1 -1
- package/models/routing/redux/invokeSearch.d.ts +22 -0
- package/models/routing/redux/selectors.d.ts +47 -4
- package/models/routing/util/expressions.d.ts +1 -1
- package/models/routing/util/find-contenttype-mapping.d.ts +3 -1
- package/models/search/containers/withListing.d.ts +1 -1
- package/models/search/containers/withSearch.d.ts +1 -1
- package/models/search/models/Queries.d.ts +3 -5
- package/models/search/models/Search.d.ts +43 -13
- package/models/search/models/SearchActions.d.ts +61 -18
- package/models/search/models/SearchProps.d.ts +11 -10
- package/models/search/models/SearchState.d.ts +23 -2
- package/models/search/models/SearchUtil.d.ts +3 -3
- package/models/search/redux/getIn.d.ts +2 -2
- package/models/search/redux/reducers.d.ts +3 -4
- package/models/search/redux/sagas.d.ts +13 -14
- package/models/search/redux/schema.d.ts +3 -3
- package/models/search/redux/selectors.d.ts +64 -42
- package/models/search/redux/util.d.ts +10 -1
- package/models/search/search/ContensisDeliveryApi.d.ts +6 -26
- package/models/search/search/expressions.d.ts +6 -4
- package/models/search/search/util.d.ts +9 -7
- package/models/search/transformations/state-to-queryparams.mapper.d.ts +1 -1
- package/models/server/features/linkdepth-api/search.d.ts +1 -1
- package/models/server/features/response-handler/render-stream.d.ts +2 -4
- package/models/server/features/static-assets/index.d.ts +4 -3
- package/models/server/internalServer.d.ts +1 -2
- package/models/server/middleware/subsiteDebug.d.ts +11 -0
- package/models/server/root.d.ts +3 -0
- package/models/server/util/bundles.d.ts +9 -9
- package/models/server/util/jsx.d.ts +2 -14
- package/models/user/hocs/withRegistration.d.ts +1 -1
- package/models/util/CachedDeliveryApi.d.ts +8 -2
- package/models/util/ContensisDeliveryApi.d.ts +2 -4
- package/models/util/NoSSR.d.ts +6 -0
- package/models/util/SSRContext.d.ts +3 -19
- package/models/util/donotuse_useHistory.d.ts +6 -0
- package/models/util/errors.d.ts +16 -0
- package/models/util/index.d.ts +7 -2
- package/models/util/subsite.d.ts +12 -0
- package/models/util/urls.d.ts +1 -2
- package/models/util/useIsClient.d.ts +6 -0
- package/package.json +39 -38
- package/cjs/App-vZrUfVgQ.js.map +0 -1
- package/cjs/ChangePassword.container-ECjEXixF.js.map +0 -1
- package/cjs/CookieHelper.class-C3Eqoze9.js.map +0 -1
- package/cjs/RouteLoader-D5Yg7EB5.js.map +0 -1
- package/cjs/SSRContext-DVj_QAC1.js.map +0 -1
- package/cjs/ToJs-C9jwV7YB.js.map +0 -1
- package/cjs/VersionInfo-B_dKCubg.js.map +0 -1
- package/cjs/sagas-CbZhaRNd.js.map +0 -1
- package/cjs/selectors-wCs5fHD4.js.map +0 -1
- package/cjs/store-D07FOXvM.js.map +0 -1
- package/cjs/version-B7XFkBhY.js.map +0 -1
- package/esm/App-DLZweVSp.js.map +0 -1
- package/esm/ChangePassword.container-BgzIy8dA.js.map +0 -1
- package/esm/CookieHelper.class-FTURFpz3.js.map +0 -1
- package/esm/RouteLoader-xeQBXywk.js.map +0 -1
- package/esm/SSRContext-BE8ElZ3X.js.map +0 -1
- package/esm/ToJs-CNzfvyxJ.js.map +0 -1
- package/esm/VersionInfo-Cno7K0OA.js.map +0 -1
- package/esm/sagas-xJU-zOpn.js.map +0 -1
- package/esm/selectors-DO2ocdOp.js.map +0 -1
- package/esm/store-3u0RzHZ0.js.map +0 -1
- package/esm/version-BlsI7hX2.js.map +0 -1
- package/models/redux/store/injectors.d.ts +0 -31
- package/models/search/search/ToJs.d.ts +0 -4
|
@@ -2,23 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var ContensisDeliveryApi = require('./ContensisDeliveryApi-gN3_MHEl.js');
|
|
6
6
|
var contensisDeliveryApi = require('contensis-delivery-api');
|
|
7
7
|
var React = require('react');
|
|
8
8
|
var reactRedux = require('react-redux');
|
|
9
|
+
var slice = require('./slice-5xJMH24n.js');
|
|
9
10
|
var mapJson = require('jsonpath-mapper');
|
|
10
|
-
var sagas = require('./sagas-
|
|
11
|
+
var sagas = require('./sagas-OfBUtx74.js');
|
|
11
12
|
require('reselect');
|
|
12
13
|
require('immer');
|
|
13
14
|
require('deep-equal');
|
|
14
15
|
require('deepmerge');
|
|
15
16
|
require('query-string');
|
|
16
17
|
var contensisCoreApi = require('contensis-core-api');
|
|
17
|
-
var
|
|
18
|
+
var urls = require('./urls-DGZlAs0y.js');
|
|
18
19
|
require('isomorphic-fetch');
|
|
19
20
|
var express = require('express');
|
|
20
21
|
var http = require('http');
|
|
21
22
|
var httpProxy = require('http-proxy');
|
|
23
|
+
var App = require('./App-TTUKj85f.js');
|
|
22
24
|
var fs = require('fs');
|
|
23
25
|
var path = require('path');
|
|
24
26
|
var appRootPath = require('app-root-path');
|
|
@@ -29,31 +31,38 @@ var styled = require('styled-components');
|
|
|
29
31
|
var serialize = require('serialize-javascript');
|
|
30
32
|
var lodash = require('lodash');
|
|
31
33
|
var lodashClean = require('lodash-clean');
|
|
32
|
-
var CookieHelper_class = require('./CookieHelper.class-
|
|
34
|
+
var CookieHelper_class = require('./CookieHelper.class-Det3qfdU.js');
|
|
33
35
|
var cookiesMiddleware = require('universal-cookie-express');
|
|
34
|
-
var store = require('./store-
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var RouteLoader = require('./RouteLoader-D5Yg7EB5.js');
|
|
36
|
+
var store = require('./store-Dn7vP6G0.js');
|
|
37
|
+
var version = require('./version-2FamXHhj.js');
|
|
38
|
+
var selectors = require('./selectors-BrxJ8-F8.js');
|
|
39
|
+
var RouteLoader = require('./RouteLoader-BM8DyfcF.js');
|
|
39
40
|
var stream = require('stream');
|
|
40
41
|
var server$2 = require('@loadable/server');
|
|
41
42
|
var chalk = require('chalk');
|
|
42
43
|
var minifyCssString = require('minify-css-string');
|
|
43
44
|
var reactCookie = require('react-cookie');
|
|
45
|
+
var reactHelmetAsync = require('react-helmet-async');
|
|
44
46
|
var server$3 = require('react-router-dom/server');
|
|
47
|
+
var SSRContext = require('./SSRContext-DotLlTQc.js');
|
|
48
|
+
require('./VersionInfo-zFPsvS8q.js');
|
|
49
|
+
require('./CookieConstants-DfPiWCRZ.js');
|
|
50
|
+
require('@reduxjs/toolkit');
|
|
45
51
|
require('loglevel');
|
|
46
52
|
require('@redux-saga/core/effects');
|
|
53
|
+
require('./version-rFG9Y6_B.js');
|
|
54
|
+
require('./util-wQwG9vit.js');
|
|
55
|
+
require('./selectors-DAQR0uZa.js');
|
|
47
56
|
require('./_commonjsHelpers-BJu3ubxk.js');
|
|
48
|
-
require('
|
|
57
|
+
require('history');
|
|
58
|
+
require('await-to-js');
|
|
59
|
+
require('./ChangePassword.container-C4Du3Wb1.js');
|
|
60
|
+
require('./matchGroups-dqONU-vY.js');
|
|
61
|
+
require('./ToJs-BsWqWjdm.js');
|
|
49
62
|
require('redux');
|
|
50
63
|
require('redux-thunk');
|
|
51
64
|
require('redux-saga');
|
|
52
65
|
require('redux-injectors-19');
|
|
53
|
-
require('history');
|
|
54
|
-
require('await-to-js');
|
|
55
|
-
require('./ChangePassword.container-ECjEXixF.js');
|
|
56
|
-
require('./ToJs-C9jwV7YB.js');
|
|
57
66
|
|
|
58
67
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
59
68
|
|
|
@@ -64,6 +73,7 @@ var http__default = /*#__PURE__*/_interopDefault(http);
|
|
|
64
73
|
var httpProxy__default = /*#__PURE__*/_interopDefault(httpProxy);
|
|
65
74
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
66
75
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
76
|
+
var appRootPath__default = /*#__PURE__*/_interopDefault(appRootPath);
|
|
67
77
|
var serialize__default = /*#__PURE__*/_interopDefault(serialize);
|
|
68
78
|
var cookiesMiddleware__default = /*#__PURE__*/_interopDefault(cookiesMiddleware);
|
|
69
79
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
@@ -240,7 +250,7 @@ const resolveParentEntries = async (parentContentTypeIds, replaceContentTypeIds,
|
|
|
240
250
|
});
|
|
241
251
|
query.fields = params.fields ? [...JSON.parse(params.fields), parentFieldId] : [];
|
|
242
252
|
if (debug) console.log(`\nResolve parent entries query: \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
|
|
243
|
-
const parentResults = await
|
|
253
|
+
const parentResults = await ContensisDeliveryApi.cachedSearch.searchUsingPost(query, Number(params.linkDepth || 0), params.projectId);
|
|
244
254
|
return mergeResults(results, Util.GetItems(parentResults), replaceContentTypeIds, parentFieldId);
|
|
245
255
|
};
|
|
246
256
|
|
|
@@ -286,7 +296,7 @@ class QueryLevelResults {
|
|
|
286
296
|
}
|
|
287
297
|
if (runFirstQuery) {
|
|
288
298
|
if (this.debug) console.log(`\nLevel ${this.level} - First query: \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
|
|
289
|
-
this.firstResults = await
|
|
299
|
+
this.firstResults = await ContensisDeliveryApi.cachedSearch.searchUsingPost(query, 0, params.projectId);
|
|
290
300
|
|
|
291
301
|
// mapResultsToValidatedLinks
|
|
292
302
|
for (const linkFieldId of this.linkFieldIds) {
|
|
@@ -323,7 +333,7 @@ class QueryLevelResults {
|
|
|
323
333
|
}
|
|
324
334
|
if (runFinalQuery) {
|
|
325
335
|
if (this.debug) console.log(`\nLevel ${this.level} - Final query: \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
|
|
326
|
-
this.finalResults = await
|
|
336
|
+
this.finalResults = await ContensisDeliveryApi.cachedSearch.searchUsingPost(query, Number(params.linkDepth) || 0, params.projectId);
|
|
327
337
|
if (this.parent) this.parent.runFinalQuery = true;
|
|
328
338
|
|
|
329
339
|
// mapResultsToValidatedLinks
|
|
@@ -464,7 +474,7 @@ class LinkDepthSearchService {
|
|
|
464
474
|
};
|
|
465
475
|
})) || []);
|
|
466
476
|
if (this.debug) console.log(`\nFinal query: ${derivedIds.reduce((accumulator, object) => accumulator + object.entryIds.length, 0)} derived ids \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
|
|
467
|
-
const finalQueryResult = await
|
|
477
|
+
const finalQueryResult = await ContensisDeliveryApi.cachedSearch.searchUsingPost(query, Number(params.linkDepth) || 0, params.projectId);
|
|
468
478
|
|
|
469
479
|
// Resolve any parent entries
|
|
470
480
|
|
|
@@ -591,7 +601,7 @@ const makeLinkDepthMiddleware = ({
|
|
|
591
601
|
const linkDepthMiddleware = async (req, res) => {
|
|
592
602
|
try {
|
|
593
603
|
// Short cache duration copied from canterbury project
|
|
594
|
-
|
|
604
|
+
urls.setCachingHeaders(res, {
|
|
595
605
|
cacheControl: 'private',
|
|
596
606
|
surrogateControl: '10'
|
|
597
607
|
});
|
|
@@ -627,42 +637,66 @@ const makeLinkDepthMiddleware = ({
|
|
|
627
637
|
}
|
|
628
638
|
};
|
|
629
639
|
|
|
640
|
+
/**
|
|
641
|
+
* Development proxy for Subsite PoC
|
|
642
|
+
* Catch all routes before they hit CRB handlers
|
|
643
|
+
* and rewrite them to include the subsite base path,
|
|
644
|
+
* this allows us to run the subsite in a subfolder in development
|
|
645
|
+
* In production we will handle this with a path rewrite in the Cloud Dashboard site configuration,
|
|
646
|
+
* @param subsitePath the content base path we will rewrite to
|
|
647
|
+
* @param exceptions an array of path prefixes to ignore when rewriting, useful for ignoring assets that do not live in the subsite base path
|
|
648
|
+
*/
|
|
649
|
+
const subsiteDebugMiddleware = (subsitePath, exceptions = []) => (req, res, next) => {
|
|
650
|
+
if (!subsitePath || req.hostname !== 'localhost' || req.path.startsWith('/api/') || exceptions.some(exception => req.path.startsWith(exception))) return next();
|
|
651
|
+
if (!req.path.startsWith(`${subsitePath}/`)) {
|
|
652
|
+
console.warn(`[subsite-debug-middleware] Rewriting (${subsitePath})${req.url}`);
|
|
653
|
+
if (req.path === '/' || req.path === subsitePath) req.url = subsitePath;else req.url = `${subsitePath}${req.url}`;
|
|
654
|
+
res.setHeader('x-crb-subsite-content-path', req.url);
|
|
655
|
+
|
|
656
|
+
// Important to set the subsite_path header as this drives the subsite-scoped routing logic
|
|
657
|
+
req.headers['subsite_path'] = subsitePath;
|
|
658
|
+
}
|
|
659
|
+
next();
|
|
660
|
+
};
|
|
661
|
+
|
|
630
662
|
const servers$1 = SERVERS; /* global SERVERS */
|
|
631
663
|
const project = PROJECT; /* global PROJECT */
|
|
632
664
|
const alias$1 = ALIAS; /* global ALIAS */
|
|
633
|
-
const deliveryApiHostname =
|
|
665
|
+
const deliveryApiHostname = urls.urls(alias$1, project).api;
|
|
666
|
+
const proxyTimeoutMs = 45_000;
|
|
634
667
|
const assetProxy = httpProxy__default.default.createProxyServer();
|
|
635
668
|
const deliveryProxy = httpProxy__default.default.createProxyServer();
|
|
636
669
|
const reverseProxies = (app, reverseProxyPaths = []) => {
|
|
637
670
|
deliveryApiProxy(deliveryProxy, app);
|
|
638
|
-
app.all(reverseProxyPaths
|
|
639
|
-
|
|
671
|
+
app.all(reverseProxyPaths.map(proxyPath =>
|
|
672
|
+
// Patch to update paths for express v5
|
|
673
|
+
proxyPath.endsWith('/*') ? `${proxyPath.slice(0, -2)}/{*splat}` : proxyPath.endsWith('/**') ? `${proxyPath.slice(0, -3)}/{*splat}` : proxyPath), (req, res) => {
|
|
674
|
+
const target = req.hostname.includes('preview-') || req.hostname.includes('preview.') || req.hostname === 'localhost' ? servers$1.previewIis || servers$1.iis : servers$1.iis;
|
|
640
675
|
assetProxy.web(req, res, {
|
|
641
676
|
target,
|
|
642
|
-
changeOrigin: true
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
/* eslint-disable no-console */
|
|
646
|
-
console.log(`Proxy Request for ${req.path} HostName:${req.hostname} failed with ${e}`);
|
|
647
|
-
/* eslint-enable no-console */
|
|
677
|
+
changeOrigin: true,
|
|
678
|
+
proxyTimeout: proxyTimeoutMs,
|
|
679
|
+
timeout: proxyTimeoutMs
|
|
648
680
|
});
|
|
649
681
|
});
|
|
682
|
+
assetProxy.on('error', (e, req) => {
|
|
683
|
+
console.log(`[assetProxy] "${req.method} ${req.url}" host: ${req.headers.host} failed with ${e}`);
|
|
684
|
+
});
|
|
650
685
|
};
|
|
651
686
|
const deliveryApiProxy = (apiProxy, app) => {
|
|
652
687
|
// This is just here to stop cors requests on localhost. In Production this is mapped using varnish.
|
|
653
|
-
app.all(['/api/delivery
|
|
654
|
-
|
|
655
|
-
console.log(`Proxying api request to ${servers$1.alias}`);
|
|
688
|
+
app.all(['/api/delivery/{*splat}', '/api/forms/{*splat}', '/api/image/{*splat}', '/authenticate/{*splat}'], (req, res) => {
|
|
689
|
+
console.log(`[apiProxy] "${req.method} ${App.shorten(req.url)}" target: ${servers$1.alias}`);
|
|
656
690
|
apiProxy.web(req, res, {
|
|
657
691
|
target: deliveryApiHostname,
|
|
658
|
-
changeOrigin: true
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
/* eslint-disable no-console */
|
|
662
|
-
console.log(`Proxy request for ${req.path} HostName:${req.hostname} failed with ${e}`);
|
|
663
|
-
/* eslint-enable no-console */
|
|
692
|
+
changeOrigin: true,
|
|
693
|
+
proxyTimeout: proxyTimeoutMs,
|
|
694
|
+
timeout: proxyTimeoutMs
|
|
664
695
|
});
|
|
665
696
|
});
|
|
697
|
+
apiProxy.on('error', (e, req) => {
|
|
698
|
+
console.log(`[apiProxy] "${req.method} ${req.url}" host: ${req.headers.host} failed with ${e}`);
|
|
699
|
+
});
|
|
666
700
|
};
|
|
667
701
|
|
|
668
702
|
const CacheDuration = {
|
|
@@ -737,9 +771,8 @@ const resolveStartupMiddleware = ({
|
|
|
737
771
|
if (maxage) res.set('Cache-Control', `public, max-age=${maxage}`);
|
|
738
772
|
res.sendFile(startupFileLocation);
|
|
739
773
|
} catch (sendFileError) {
|
|
740
|
-
// eslint-disable-next-line no-console
|
|
741
774
|
console.log(`Unable to send file startup.js at '${startupFileLocation}'`, sendFileError);
|
|
742
|
-
|
|
775
|
+
res.status(404).send();
|
|
743
776
|
}
|
|
744
777
|
} else {
|
|
745
778
|
next();
|
|
@@ -747,8 +780,11 @@ const resolveStartupMiddleware = ({
|
|
|
747
780
|
};
|
|
748
781
|
|
|
749
782
|
// Serving static assets
|
|
783
|
+
const {
|
|
784
|
+
path: appPath
|
|
785
|
+
} = appRootPath__default.default;
|
|
750
786
|
const staticAssets = (app, {
|
|
751
|
-
appRootPath
|
|
787
|
+
appRootPath = appPath,
|
|
752
788
|
scripts = {},
|
|
753
789
|
startupScriptFilename = 'startup.js',
|
|
754
790
|
staticFolderPath = 'static',
|
|
@@ -756,20 +792,18 @@ const staticAssets = (app, {
|
|
|
756
792
|
staticRoutePaths = []
|
|
757
793
|
}) => {
|
|
758
794
|
app.use([`/${staticRoutePath}`, ...staticRoutePaths.map(p => `/${p}`), `/${staticFolderPath}`], bundleManipulationMiddleware({
|
|
759
|
-
appRootPath
|
|
795
|
+
appRootPath,
|
|
760
796
|
// these maxage values are different in config but the same in runtime,
|
|
761
797
|
// this one is the true value in seconds
|
|
762
798
|
maxage: CacheDuration.static,
|
|
763
799
|
staticFolderPath,
|
|
764
800
|
staticRoutePath
|
|
765
801
|
}), resolveStartupMiddleware({
|
|
766
|
-
appRootPath
|
|
802
|
+
appRootPath,
|
|
767
803
|
maxage: CacheDuration.static,
|
|
768
804
|
startupScriptFilename: scripts.startup || startupScriptFilename,
|
|
769
805
|
staticFolderPath
|
|
770
|
-
}),
|
|
771
|
-
// eslint-disable-next-line import/no-named-as-default-member
|
|
772
|
-
express__default.default.static(`dist/${staticFolderPath}`, {
|
|
806
|
+
}), express__default.default.static(`dist/${staticFolderPath}`, {
|
|
773
807
|
// these maxage values are different in config but the same in runtime,
|
|
774
808
|
// this one is somehow converted and should end up being the same as CacheDuration.static
|
|
775
809
|
maxAge: CacheDuration.expressStatic
|
|
@@ -819,32 +853,59 @@ const handleResponse = (request, response, content, send = 'send') => {
|
|
|
819
853
|
* @param response the express Response object
|
|
820
854
|
* @param stream all chunks are piped to this stream to add additional style elements to each streamed chunk
|
|
821
855
|
*/
|
|
822
|
-
const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
823
|
-
|
|
824
|
-
let
|
|
856
|
+
const renderStream = (getContextHtml, jsx, request, response, stream) => {
|
|
857
|
+
// Store timeout reference for cleanup on normal or abnormal termination
|
|
858
|
+
let timeoutId = null;
|
|
859
|
+
const disposeTimeout = () => {
|
|
860
|
+
if (timeoutId) {
|
|
861
|
+
clearTimeout(timeoutId);
|
|
862
|
+
timeoutId = null;
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
// Only used for abnormal termination
|
|
867
|
+
const abortCleanup = err => {
|
|
868
|
+
disposeTimeout();
|
|
869
|
+
stream.destroy(err instanceof Error ? err : undefined);
|
|
870
|
+
abort();
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
// Guard against client disconnect
|
|
874
|
+
request.on('close', () => abortCleanup());
|
|
875
|
+
|
|
876
|
+
// Guard against transform errors
|
|
877
|
+
stream.on('error', err => {
|
|
878
|
+
abortCleanup(err);
|
|
879
|
+
if (!response.headersSent) response.destroy(err);
|
|
880
|
+
});
|
|
825
881
|
const {
|
|
826
882
|
abort,
|
|
827
883
|
pipe
|
|
828
884
|
} = server$1.renderToPipeableStream(jsx, {
|
|
829
885
|
onShellReady() {
|
|
830
|
-
const html = getContextHtml();
|
|
886
|
+
const html = getContextHtml(false);
|
|
831
887
|
if (!html) {
|
|
832
888
|
// this means we have finished with the response already
|
|
833
|
-
|
|
889
|
+
abortCleanup();
|
|
834
890
|
} else {
|
|
835
|
-
|
|
891
|
+
const header = html.split('{{APP}}')[0];
|
|
836
892
|
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
837
893
|
stream.write(header);
|
|
838
894
|
pipe(stream);
|
|
839
895
|
}
|
|
840
896
|
},
|
|
841
897
|
onAllReady() {
|
|
898
|
+
const footer = getContextHtml(true).split('{{APP}}')[1];
|
|
842
899
|
stream.write(footer);
|
|
900
|
+
disposeTimeout(); // Clear the timeout, let stream end naturally
|
|
843
901
|
},
|
|
844
902
|
onShellError(error) {
|
|
845
|
-
|
|
846
|
-
response.
|
|
847
|
-
|
|
903
|
+
abortCleanup(error); // Abnormal - destroy everything
|
|
904
|
+
if (!response.headersSent) {
|
|
905
|
+
response.statusCode = 500;
|
|
906
|
+
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
907
|
+
response.send('<h1>Something went wrong</h1>');
|
|
908
|
+
}
|
|
848
909
|
console.error(`[renderToPipeableStream:onShellError]`, error);
|
|
849
910
|
},
|
|
850
911
|
onError(error) {
|
|
@@ -852,10 +913,13 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
852
913
|
}
|
|
853
914
|
});
|
|
854
915
|
|
|
855
|
-
// Abandon and switch to client rendering
|
|
916
|
+
// Abandon and switch to client rendering after 30s.
|
|
856
917
|
// Try lowering this to see the client recover.
|
|
857
|
-
setTimeout(() =>
|
|
858
|
-
|
|
918
|
+
timeoutId = setTimeout(() => {
|
|
919
|
+
timeoutId = null;
|
|
920
|
+
abortCleanup();
|
|
921
|
+
}, 30_000);
|
|
922
|
+
stream.pipe(response);
|
|
859
923
|
};
|
|
860
924
|
|
|
861
925
|
/**
|
|
@@ -895,6 +959,23 @@ const styledComponentsStream = sheet => {
|
|
|
895
959
|
this.push(styledCSS + renderedHtml);
|
|
896
960
|
}
|
|
897
961
|
callback();
|
|
962
|
+
},
|
|
963
|
+
destroy(err, callback) {
|
|
964
|
+
// Called on both stream.destroy() and natural end
|
|
965
|
+
// Stops the sheet intercepting styles & releases its references
|
|
966
|
+
|
|
967
|
+
// try/catch is required if sheet.seal() throws for any reason,
|
|
968
|
+
// callback(err) must still be called, as Node.js stream internals depend
|
|
969
|
+
// on it to complete teardown. Omitting it causes the stream to hang.
|
|
970
|
+
try {
|
|
971
|
+
sheet.seal();
|
|
972
|
+
} catch (sealErr) {
|
|
973
|
+
// Catch any errors from sealing the sheet, we MUST always call the
|
|
974
|
+
// callback to prevent hanging the stream
|
|
975
|
+
|
|
976
|
+
console.error('[styledComponentsStream] sheet.seal() failed - styles may leak:', sealErr);
|
|
977
|
+
}
|
|
978
|
+
callback(err);
|
|
898
979
|
}
|
|
899
980
|
});
|
|
900
981
|
return readerWriter;
|
|
@@ -947,7 +1028,8 @@ const loadableChunkExtractors = () => {
|
|
|
947
1028
|
statsFile: path__default.default.resolve('dist/legacy/loadable-stats.json')
|
|
948
1029
|
});
|
|
949
1030
|
} catch (e) {
|
|
950
|
-
|
|
1031
|
+
// legacy bundling deprecated in v4
|
|
1032
|
+
// console.info('@loadable/server legacy ChunkExtractor not available');
|
|
951
1033
|
}
|
|
952
1034
|
commonLoadableExtractor.addChunk = chunk => {
|
|
953
1035
|
var _modern, _legacy, _legacy2;
|
|
@@ -1055,6 +1137,7 @@ const unhandledExceptionHandler = (handleExceptions = handleDefaultEvents) => {
|
|
|
1055
1137
|
}
|
|
1056
1138
|
};
|
|
1057
1139
|
|
|
1140
|
+
const logPrefix = '[addHeaders]';
|
|
1058
1141
|
const addStandardHeaders = (state, response, packagejson, groups) => {
|
|
1059
1142
|
if (state) {
|
|
1060
1143
|
try {
|
|
@@ -1068,14 +1151,14 @@ const addStandardHeaders = (state, response, packagejson, groups) => {
|
|
|
1068
1151
|
// - add `any-update` header that will indiscriminately
|
|
1069
1152
|
// invalidate the SSR page cache when any content is updated
|
|
1070
1153
|
const addAnyUpdateHeader = routingSurrogateKeys.length >= 2000 || response.statusCode >= 400 || anyApiError;
|
|
1071
|
-
console.info(
|
|
1154
|
+
console.info(`${logPrefix} ${addAnyUpdateHeader ? anyUpdateHeader : routingSurrogateKeys.length} surrogate keys for ${response.req.url}`);
|
|
1072
1155
|
const surrogateKeys = addAnyUpdateHeader ? anyUpdateHeader : routingSurrogateKeys.join(' ');
|
|
1073
1156
|
const surrogateKeyHeader = `${packagejson.name}-app ${surrogateKeys}`;
|
|
1074
1157
|
response.setHeader('surrogate-key', surrogateKeyHeader);
|
|
1075
1158
|
addVarnishAuthenticationHeaders(state, response, groups);
|
|
1076
1159
|
response.setHeader('surrogate-control', `max-age=${getCacheDuration(response.statusCode)}`);
|
|
1077
1160
|
} catch (e) {
|
|
1078
|
-
console.info(
|
|
1161
|
+
console.info(`${logPrefix} Error adding headers`, e.message);
|
|
1079
1162
|
}
|
|
1080
1163
|
}
|
|
1081
1164
|
};
|
|
@@ -1088,14 +1171,13 @@ const addVarnishAuthenticationHeaders = (state, response, groups = {}) => {
|
|
|
1088
1171
|
globalGroups,
|
|
1089
1172
|
allowedGroups
|
|
1090
1173
|
} = groups;
|
|
1091
|
-
// console.info(globalGroups, allowedGroups);
|
|
1092
1174
|
let allGroups = Array.from(globalGroups && globalGroups[project] || {});
|
|
1093
1175
|
if (stateEntry && selectors.getImmutableOrJS(stateEntry, ['authentication', 'isLoginRequired']) && allowedGroups && allowedGroups[project]) {
|
|
1094
1176
|
allGroups = [...allGroups, ...allowedGroups[project]];
|
|
1095
1177
|
}
|
|
1096
1178
|
response.header('x-contensis-viewer-groups', allGroups.join('|'));
|
|
1097
1179
|
} catch (e) {
|
|
1098
|
-
console.info(
|
|
1180
|
+
console.info(`${logPrefix} Error adding authentication header`, e);
|
|
1099
1181
|
}
|
|
1100
1182
|
}
|
|
1101
1183
|
};
|
|
@@ -1121,14 +1203,17 @@ const replaceHtml = ({
|
|
|
1121
1203
|
let responseHTML = '';
|
|
1122
1204
|
// Serve a blank HTML page with client scripts to load the app in the browser
|
|
1123
1205
|
if (accessMethod.DYNAMIC) {
|
|
1124
|
-
responseHTML = templateHTML.replace('{{TITLE}}', '').replace('{{SEO_CRITICAL_METADATA}}', '').replace('{{CRITICAL_CSS}}', '').replace('{{APP}}', '')
|
|
1206
|
+
responseHTML = templateHTML.replace('{{TITLE}}', '').replace('{{SEO_CRITICAL_METADATA}}', '').replace('{{CRITICAL_CSS}}', '').replace('{{APP}}', '')
|
|
1207
|
+
// .replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1208
|
+
.replace('{{REDUX_DATA}}', state);
|
|
1125
1209
|
}
|
|
1126
1210
|
|
|
1127
1211
|
// Page fragment served with client scripts and redux data that hydrate the app client side
|
|
1128
1212
|
else if (accessMethod.FRAGMENT && !accessMethod.STATIC) {
|
|
1129
1213
|
responseHTML = templateHTMLFragment.replace('{{TITLE}}', title).replace('{{SEO_CRITICAL_METADATA}}', metadata).replace('{{CRITICAL_CSS}}', minifyCssString__default.default(styleTags))
|
|
1130
1214
|
//.replace('{{APP}}', html)
|
|
1131
|
-
.replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1215
|
+
// .replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1216
|
+
.replace('{{REDUX_DATA}}', state);
|
|
1132
1217
|
}
|
|
1133
1218
|
|
|
1134
1219
|
// Full HTML page served statically
|
|
@@ -1142,7 +1227,8 @@ const replaceHtml = ({
|
|
|
1142
1227
|
else if (!accessMethod.FRAGMENT && !accessMethod.STATIC) {
|
|
1143
1228
|
responseHTML = templateHTML.replace('{{TITLE}}', title).replace('{{SEO_CRITICAL_METADATA}}', metadata).replace('{{CRITICAL_CSS}}', styleTags)
|
|
1144
1229
|
//.replace('{{APP}}', html)
|
|
1145
|
-
.replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1230
|
+
// .replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1231
|
+
.replace('{{REDUX_DATA}}', state);
|
|
1146
1232
|
}
|
|
1147
1233
|
|
|
1148
1234
|
// If react-helmet htmlAttributes are being used,
|
|
@@ -1151,7 +1237,12 @@ const replaceHtml = ({
|
|
|
1151
1237
|
if (htmlAttributes) {
|
|
1152
1238
|
responseHTML = responseHTML.replace(/<html?.+?>/, `<html ${htmlAttributes}>`);
|
|
1153
1239
|
}
|
|
1154
|
-
|
|
1240
|
+
responseHTML = html ? responseHTML.replace('{{APP}}', html) : responseHTML;
|
|
1241
|
+
|
|
1242
|
+
// Only replace bundle tags at the very end when we have rendered and are
|
|
1243
|
+
// streaming out the HTML "footer"
|
|
1244
|
+
if (bundleTags) responseHTML = responseHTML.replace('{{LOADABLE_CHUNKS}}', bundleTags);
|
|
1245
|
+
return responseHTML;
|
|
1155
1246
|
};
|
|
1156
1247
|
|
|
1157
1248
|
/**
|
|
@@ -1163,13 +1254,15 @@ const replaceHtml = ({
|
|
|
1163
1254
|
*/
|
|
1164
1255
|
const ssrJsxProducer = (ReactApp, {
|
|
1165
1256
|
providers,
|
|
1166
|
-
props
|
|
1167
|
-
ssrAssets
|
|
1257
|
+
props
|
|
1258
|
+
// ssrAssets,
|
|
1168
1259
|
}) => {
|
|
1169
1260
|
var _providers$styledComp;
|
|
1170
1261
|
// Recast ChunkExtractorManager to avoid TS error `Property 'children' does not exist on type...`
|
|
1171
1262
|
const ChunkExtractor = server$2.ChunkExtractorManager;
|
|
1172
|
-
const jsx = /*#__PURE__*/React__default.default.createElement(
|
|
1263
|
+
const jsx = /*#__PURE__*/React__default.default.createElement(reactHelmetAsync.HelmetProvider, {
|
|
1264
|
+
context: providers.helmet
|
|
1265
|
+
}, /*#__PURE__*/React__default.default.createElement(ChunkExtractor, {
|
|
1173
1266
|
extractor: providers.loadable.extractor
|
|
1174
1267
|
}, /*#__PURE__*/React__default.default.createElement(reactCookie.CookiesProvider, {
|
|
1175
1268
|
cookies: providers.cookies
|
|
@@ -1178,16 +1271,20 @@ const ssrJsxProducer = (ReactApp, {
|
|
|
1178
1271
|
}, /*#__PURE__*/React__default.default.createElement(RouteLoader.HttpContext.Provider, {
|
|
1179
1272
|
value: providers.httpContext
|
|
1180
1273
|
}, /*#__PURE__*/React__default.default.createElement(server$3.StaticRouter, {
|
|
1181
|
-
location: providers.router.url
|
|
1274
|
+
location: providers.router.url,
|
|
1275
|
+
future: {
|
|
1276
|
+
v7_startTransition: true,
|
|
1277
|
+
v7_relativeSplatPath: true
|
|
1278
|
+
}
|
|
1182
1279
|
}, /*#__PURE__*/React__default.default.createElement(SSRContext.SSRContextProvider, {
|
|
1183
1280
|
accessMethod: providers.ssrContext.accessMethod,
|
|
1184
1281
|
request: providers.ssrContext.request,
|
|
1185
|
-
response: providers.ssrContext.response
|
|
1186
|
-
|
|
1282
|
+
response: providers.ssrContext.response
|
|
1283
|
+
// ssrAssets={ssrAssets}
|
|
1187
1284
|
}, /*#__PURE__*/React__default.default.createElement(ReactApp, {
|
|
1188
1285
|
routes: props.routes,
|
|
1189
1286
|
withEvents: props.withEvents
|
|
1190
|
-
})))))));
|
|
1287
|
+
}))))))));
|
|
1191
1288
|
|
|
1192
1289
|
// Wrap the JSX in a StyleSheetManager if a ServerStyleSheet is provided
|
|
1193
1290
|
return !((_providers$styledComp = providers.styledComponents) !== null && _providers$styledComp !== void 0 && _providers$styledComp.sheet) ? jsx : providers.styledComponents.sheet.collectStyles(jsx);
|
|
@@ -1195,7 +1292,7 @@ const ssrJsxProducer = (ReactApp, {
|
|
|
1195
1292
|
|
|
1196
1293
|
const webApp = (app, ReactApp, config) => {
|
|
1197
1294
|
const {
|
|
1198
|
-
stateType = '
|
|
1295
|
+
stateType = 'js',
|
|
1199
1296
|
routes,
|
|
1200
1297
|
withReducers,
|
|
1201
1298
|
withSagas,
|
|
@@ -1209,8 +1306,12 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1209
1306
|
disableSsrRedux,
|
|
1210
1307
|
enableSsrCookies,
|
|
1211
1308
|
handleResponses,
|
|
1212
|
-
handleExceptions = true
|
|
1309
|
+
handleExceptions = true,
|
|
1310
|
+
i18n
|
|
1213
1311
|
} = config;
|
|
1312
|
+
|
|
1313
|
+
// process locales in static routes for i18n
|
|
1314
|
+
const localeRoutes = App.createLocaleRoutes(routes);
|
|
1214
1315
|
const staticRoutePath = config.staticRoutePath || staticFolderPath;
|
|
1215
1316
|
let isRenderingJsxToString = config.renderToString || false;
|
|
1216
1317
|
const bundleData = getBundleData(config, staticRoutePath);
|
|
@@ -1224,8 +1325,16 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1224
1325
|
if (handleExceptions !== false) unhandledExceptionHandler(handleExceptions); // Create `process.on` event handlers for unhandled exceptions (Node v15+)
|
|
1225
1326
|
|
|
1226
1327
|
const versionInfo = getVersionInfo(staticFolderPath);
|
|
1227
|
-
app.get('
|
|
1228
|
-
|
|
1328
|
+
app.get('/{*splat}', cookiesMiddleware__default.default(), async (request, response) => {
|
|
1329
|
+
/*
|
|
1330
|
+
* Do not inject url directly into HTML as it can lead to XSS attacks
|
|
1331
|
+
* CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
|
|
1332
|
+
* CWE-96: Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)
|
|
1333
|
+
* Removed URL encoding as it causes inconsistencies when routes contain encoded characters in SSR
|
|
1334
|
+
* e.g. /search?category=sport%20and%20wellbeing becomes /search?category=sport%2520and%2520wellbeing
|
|
1335
|
+
* // const url = encodeURI(request.url);
|
|
1336
|
+
*/
|
|
1337
|
+
const url = request.url;
|
|
1229
1338
|
const matchedStaticRoute = reactRouterDom.matchRoutes(routes.StaticRoutes, request.path);
|
|
1230
1339
|
const isStaticRoute = matchedStaticRoute && matchedStaticRoute.length > 0;
|
|
1231
1340
|
if (isStaticRoute) {
|
|
@@ -1260,30 +1369,27 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1260
1369
|
}), stateType);
|
|
1261
1370
|
|
|
1262
1371
|
// dispatch any global and non-saga related actions before calling our JSX
|
|
1263
|
-
const versionStatus =
|
|
1372
|
+
const versionStatus = ContensisDeliveryApi.deliveryApi.getServerSideVersionStatus(request);
|
|
1264
1373
|
|
|
1265
1374
|
// In server-side blocks world, the hostname requested by the client resides in the x-orig-host header
|
|
1266
1375
|
// Because of this, we prioritize x-orig-host when setting our hostname
|
|
1267
1376
|
const hostname = request.headers['x-orig-host'] || request.hostname;
|
|
1268
|
-
|
|
1377
|
+
const subsitePath = SSRContext.getSubsitePath(request);
|
|
1378
|
+
const subsitePathScript = subsitePath ? `window.subsitePath = ${serialize__default.default(subsitePath)};` : '';
|
|
1379
|
+
console.info(`[webApp] "${request.method} ${request.path}" hostname: ${hostname} versionStatus: ${versionStatus}`);
|
|
1269
1380
|
store$1.dispatch(version.setVersionStatus(versionStatus));
|
|
1270
1381
|
store$1.dispatch(version.setVersion(versionInfo.commitRef, versionInfo.buildNo));
|
|
1271
1382
|
const project = App.pickProject(hostname, request.query);
|
|
1272
1383
|
const groups = allowedGroups && allowedGroups[project];
|
|
1273
1384
|
store$1.dispatch(selectors.setCurrentProject(project, groups, hostname));
|
|
1385
|
+
if (i18n) {
|
|
1386
|
+
store$1.dispatch(slice.actions.INIT_LOCALES({
|
|
1387
|
+
locales: {},
|
|
1388
|
+
routes: localeRoutes,
|
|
1389
|
+
...i18n
|
|
1390
|
+
}));
|
|
1391
|
+
}
|
|
1274
1392
|
const loadableExtractor = loadableChunkExtractors();
|
|
1275
|
-
|
|
1276
|
-
// type ChunkExtractorManagerPropsForReact18 = ChunkExtractorManagerProps & {
|
|
1277
|
-
// children?: React.ReactNode;
|
|
1278
|
-
// };
|
|
1279
|
-
|
|
1280
|
-
// // Recast ChunkExtractorManager to avoid TS error `Property 'children' does not exist on type...`
|
|
1281
|
-
// const ChunkExtractor = ChunkExtractorManager as ClassType<
|
|
1282
|
-
// ChunkExtractorManagerPropsForReact18,
|
|
1283
|
-
// Component<ChunkExtractorManagerPropsForReact18>,
|
|
1284
|
-
// ComponentClass<ChunkExtractorManagerPropsForReact18>
|
|
1285
|
-
// >;
|
|
1286
|
-
|
|
1287
1393
|
const ssrCookies = enableSsrCookies ?
|
|
1288
1394
|
// these cookies are managed by the cookiesMiddleware and contain listeners
|
|
1289
1395
|
// when cookies are read or written in ssr can be added to the `set-cookie` response header
|
|
@@ -1298,12 +1404,17 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1298
1404
|
// and read back any context props set by the ReactApp
|
|
1299
1405
|
const context = {};
|
|
1300
1406
|
|
|
1407
|
+
// Per-request helmet context object — populated by HelmetProvider during renderToString
|
|
1408
|
+
// Using a fresh object per request ensures thread safety under concurrent SSR requests
|
|
1409
|
+
const helmetContext = {};
|
|
1410
|
+
|
|
1301
1411
|
// Amalgamate all props for the various Providers we wrap the ReactApp with
|
|
1302
1412
|
const jsxProviderProps = {
|
|
1303
1413
|
loadable: {
|
|
1304
1414
|
extractor: loadableExtractor.commonLoadableExtractor
|
|
1305
1415
|
},
|
|
1306
1416
|
cookies: ssrCookies,
|
|
1417
|
+
helmet: helmetContext,
|
|
1307
1418
|
redux: store$1,
|
|
1308
1419
|
httpContext: context,
|
|
1309
1420
|
router: {
|
|
@@ -1333,13 +1444,10 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1333
1444
|
// Dynamic doesn't need sagas
|
|
1334
1445
|
// or styles, or any split component bundles
|
|
1335
1446
|
// nor are we streaming responses
|
|
1336
|
-
const isDynamicHints = `<script ${attributes}>window.
|
|
1447
|
+
const isDynamicHints = `<script ${attributes}>window.isDynamic = true; ${subsitePathScript}</script>`;
|
|
1337
1448
|
const jsx = ssrJsxProducer(ReactApp, {
|
|
1338
1449
|
providers: jsxProviderProps,
|
|
1339
|
-
props: jsxReactAppProps
|
|
1340
|
-
ssrAssets: {
|
|
1341
|
-
serializedState: isDynamicHints
|
|
1342
|
-
}
|
|
1450
|
+
props: jsxReactAppProps
|
|
1343
1451
|
});
|
|
1344
1452
|
server$1.renderToString(jsx);
|
|
1345
1453
|
|
|
@@ -1398,40 +1506,16 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1398
1506
|
return true;
|
|
1399
1507
|
}
|
|
1400
1508
|
if (!disableSsrRedux) {
|
|
1401
|
-
|
|
1402
|
-
// where a consumer may not be using the contensisVersionStatus in redux and calling
|
|
1403
|
-
// the `getClientSideVersionStatus()` method directly
|
|
1404
|
-
serialisedReduxData = `<script ${attributes}>window.versionStatus = "${versionStatus}"; window.REDUX_DATA = ${serialisedReduxData}</script>`;
|
|
1509
|
+
serialisedReduxData = `<script ${attributes}>${subsitePathScript} window.__USE_HYDRATE__ = true; window.REDUX_DATA = ${serialisedReduxData}</script>`;
|
|
1405
1510
|
}
|
|
1406
1511
|
}
|
|
1407
1512
|
|
|
1408
1513
|
// Responses
|
|
1409
|
-
|
|
1410
|
-
const helmet = reactHelmet.Helmet.renderStatic();
|
|
1411
|
-
reactHelmet.Helmet.rewind();
|
|
1412
|
-
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
1413
|
-
let title = helmet.title.toString();
|
|
1414
|
-
const metadata = helmet.meta.toString().concat(helmet.base.toString()).concat(helmet.link.toString()).concat(helmet.script.toString()).concat(helmet.noscript.toString());
|
|
1415
1514
|
addStandardHeaders(reduxState, response, packagejson, {
|
|
1416
1515
|
allowedGroups,
|
|
1417
1516
|
globalGroups
|
|
1418
1517
|
});
|
|
1419
|
-
|
|
1420
|
-
// After running rootSaga there should be an additional react-loadable
|
|
1421
|
-
// code-split bundles for any page components as well as core app bundles
|
|
1422
|
-
const bundleTags = getBundleTags(loadableExtractor, scripts, staticRoutePath);
|
|
1423
1518
|
const sheet = new styled.ServerStyleSheet();
|
|
1424
|
-
// Produce the ssr jsx one time so we can get any style tags to pass back in
|
|
1425
|
-
ssrJsxProducer(ReactApp, {
|
|
1426
|
-
providers: {
|
|
1427
|
-
...jsxProviderProps,
|
|
1428
|
-
styledComponents: {
|
|
1429
|
-
sheet
|
|
1430
|
-
}
|
|
1431
|
-
},
|
|
1432
|
-
props: jsxReactAppProps
|
|
1433
|
-
});
|
|
1434
|
-
let styleTags = sheet.getStyleTags();
|
|
1435
1519
|
const styledJsx = ssrJsxProducer(ReactApp, {
|
|
1436
1520
|
providers: {
|
|
1437
1521
|
...jsxProviderProps,
|
|
@@ -1439,14 +1523,31 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1439
1523
|
sheet
|
|
1440
1524
|
}
|
|
1441
1525
|
},
|
|
1442
|
-
props: jsxReactAppProps
|
|
1443
|
-
ssrAssets: {
|
|
1444
|
-
bundleTags,
|
|
1445
|
-
htmlAttributes,
|
|
1446
|
-
metadata,
|
|
1447
|
-
title
|
|
1448
|
-
}
|
|
1526
|
+
props: jsxReactAppProps
|
|
1449
1527
|
});
|
|
1528
|
+
|
|
1529
|
+
// We have to call renderToString() in order for all components to have
|
|
1530
|
+
// had chance to set the helmet metadata
|
|
1531
|
+
const html = server$1.renderToString(styledJsx);
|
|
1532
|
+
// Helmet.renderStatic() has to be called synchronously immediately after calling renderToString()
|
|
1533
|
+
// as it is not thread-safe (or specifically scoped to only this request)
|
|
1534
|
+
// TODO: deprecate `react-helmet`
|
|
1535
|
+
const helmet = reactHelmet.Helmet.renderStatic();
|
|
1536
|
+
|
|
1537
|
+
// helmetContext is populated synchronously by HelmetProvider during renderToString()
|
|
1538
|
+
// It is scoped per-request via the helmetContext object, making this thread-safe
|
|
1539
|
+
// under concurrent SSR requests (unlike the previous Helmet.renderStatic() global singleton)
|
|
1540
|
+
const {
|
|
1541
|
+
helmet: helmetAsync
|
|
1542
|
+
} = helmetContext;
|
|
1543
|
+
|
|
1544
|
+
// Because we have had to call renderToString() here to reliably gather all helmet metadata
|
|
1545
|
+
// We could potentially call sheet.getStyleTags() here too and avoid piping a react-rendered
|
|
1546
|
+
// stream to a second stream to inject styled-components CSS
|
|
1547
|
+
|
|
1548
|
+
const htmlAttributes = helmetAsync.htmlAttributes.toString() || helmet.htmlAttributes.toString();
|
|
1549
|
+
let title = helmet.title.toString().includes('><') ? helmetAsync.title.toString() : helmet.title.toString();
|
|
1550
|
+
const metadata = helmetAsync.meta.toString().concat(helmetAsync.base.toString()).concat(helmetAsync.priority.toString()).concat(helmetAsync.link.toString()).concat(helmetAsync.script.toString()).concat(helmetAsync.noscript.toString()).concat(helmet.meta.toString()).concat(helmet.base.toString()).concat(helmet.link.toString()).concat(helmet.script.toString()).concat(helmet.noscript.toString());
|
|
1450
1551
|
try {
|
|
1451
1552
|
/**
|
|
1452
1553
|
* Loads all page assets into the provided templateHTML
|
|
@@ -1457,7 +1558,8 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1457
1558
|
* we render the page as STATIC or render nothing
|
|
1458
1559
|
* if the context has requested a redirect
|
|
1459
1560
|
* */
|
|
1460
|
-
const getContextHtml =
|
|
1561
|
+
const getContextHtml = (isFinal = false, styleTags, renderedJsxMarkup) => {
|
|
1562
|
+
var _loadableExtractor$mo;
|
|
1461
1563
|
if (context.url) {
|
|
1462
1564
|
response.redirect(context.statusCode || 302, context.url);
|
|
1463
1565
|
return '';
|
|
@@ -1471,13 +1573,19 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1471
1573
|
|
|
1472
1574
|
// Set response.status from React StaticRouter
|
|
1473
1575
|
if (typeof context.statusCode === 'number') response.status(context.statusCode);
|
|
1576
|
+
const bundleTags = isFinal ? getBundleTags(loadableExtractor, scripts, staticRoutePath) : '';
|
|
1577
|
+
|
|
1578
|
+
// Getting style tags generated by "CSS Modules" because they will be
|
|
1579
|
+
// available to loadable stats if we have built parts of the app with CSS
|
|
1580
|
+
// plugins that are not within styled-components
|
|
1581
|
+
const styles = loadableExtractor === null || loadableExtractor === void 0 || (_loadableExtractor$mo = loadableExtractor.modern) === null || _loadableExtractor$mo === void 0 ? void 0 : _loadableExtractor$mo.getStyleTags();
|
|
1474
1582
|
const html = replaceHtml({
|
|
1475
1583
|
bundleTags,
|
|
1476
|
-
html:
|
|
1584
|
+
html: renderedJsxMarkup,
|
|
1477
1585
|
htmlAttributes,
|
|
1478
1586
|
metadata,
|
|
1479
1587
|
state: serialisedReduxData,
|
|
1480
|
-
styleTags
|
|
1588
|
+
styleTags: `${styleTags || ''}${styles || ''}`,
|
|
1481
1589
|
title,
|
|
1482
1590
|
templateHTML,
|
|
1483
1591
|
templateHTMLFragment,
|
|
@@ -1486,12 +1594,14 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1486
1594
|
return html;
|
|
1487
1595
|
};
|
|
1488
1596
|
if (isRenderingJsxToString) {
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
const
|
|
1597
|
+
// We have already (begrudgingly) rendered the JSX to a string above
|
|
1598
|
+
// so we can get all of the Helmet metadata out from any rendered component
|
|
1599
|
+
// const html = renderToString(styledJsx);
|
|
1600
|
+
const styleTags = sheet.getStyleTags();
|
|
1601
|
+
const responseHTML = getContextHtml(true, styleTags, html);
|
|
1492
1602
|
responseHandler(request, response, responseHTML);
|
|
1493
1603
|
} else {
|
|
1494
|
-
renderStream(getContextHtml, styledJsx, response, styledComponentsStream(sheet));
|
|
1604
|
+
renderStream(getContextHtml, styledJsx, request, response, styledComponentsStream(sheet));
|
|
1495
1605
|
}
|
|
1496
1606
|
} catch (err) {
|
|
1497
1607
|
console.info(err.message);
|
|
@@ -1554,6 +1664,7 @@ var internalServer = {
|
|
|
1554
1664
|
};
|
|
1555
1665
|
|
|
1556
1666
|
exports.ReactApp = App.AppRoot;
|
|
1667
|
+
exports.DO_NOT_COMMIT_subsiteDebugMiddleware = subsiteDebugMiddleware;
|
|
1557
1668
|
exports.default = internalServer;
|
|
1558
1669
|
exports.linkDepthApi = makeLinkDepthApi;
|
|
1559
1670
|
//# sourceMappingURL=contensis-react-base.js.map
|