@bigcommerce/stencil-cli 8.3.0 → 8.4.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/bin/stencil-bundle.js +7 -18
- package/bin/stencil-debug.js +5 -9
- package/bin/stencil-download.js +7 -19
- package/bin/stencil-init.js +4 -8
- package/bin/stencil-pull.js +5 -11
- package/bin/stencil-push.js +5 -8
- package/bin/stencil-release.js +5 -10
- package/bin/stencil-scss-autofix.js +6 -11
- package/bin/stencil-start.js +6 -9
- package/bin/stencil.js +2 -3
- package/constants.js +9 -9
- package/lib/BuildConfigManager.js +25 -23
- package/lib/Cycles.js +3 -12
- package/lib/ScssValidator.js +5 -9
- package/lib/StencilCLISettings.js +1 -3
- package/lib/StencilConfigManager.js +6 -22
- package/lib/StencilDebug.js +7 -10
- package/lib/archiveManager.js +7 -23
- package/lib/bundle-validator.js +28 -64
- package/lib/cliCommon.js +11 -21
- package/lib/commander.js +2 -3
- package/lib/content-api-client.js +5 -13
- package/lib/css/compile.js +3 -6
- package/lib/graphql/query.js +5 -8
- package/lib/lang/validator.js +5 -11
- package/lib/lang-assembler.js +4 -10
- package/lib/lang-helper.js +3 -6
- package/lib/nodeSass/AutoFixer.js +10 -19
- package/lib/nodeSass/BaseFixer.js +5 -7
- package/lib/nodeSass/BaseRulesFixer.js +3 -8
- package/lib/nodeSass/CommaRemovalFixer.js +3 -8
- package/lib/nodeSass/ConditionalImportFixer.js +3 -9
- package/lib/nodeSass/UndefinedVariableFixer.js +3 -6
- package/lib/parse-json.js +10 -9
- package/lib/regions.js +3 -23
- package/lib/release/questions.js +3 -13
- package/lib/release/release.js +16 -55
- package/lib/spinner.js +1 -2
- package/lib/stencil-bundle.js +15 -75
- package/lib/stencil-download.js +5 -6
- package/lib/stencil-download.utils.js +5 -18
- package/lib/stencil-init.js +8 -24
- package/lib/stencil-pull.js +4 -5
- package/lib/stencil-pull.utils.js +5 -28
- package/lib/stencil-push.js +3 -4
- package/lib/stencil-push.utils.js +12 -102
- package/lib/stencil-start.js +19 -48
- package/lib/store-settings-api-client.js +4 -7
- package/lib/template-assembler.js +6 -45
- package/lib/theme-api-client.js +7 -30
- package/lib/theme-config.js +16 -59
- package/lib/utils/NetworkUtils.js +6 -16
- package/lib/utils/asyncUtils.js +2 -3
- package/lib/utils/frontmatter.js +4 -5
- package/lib/utils/fsUtils.js +6 -10
- package/lib/validator/schema-translations.js +5 -7
- package/package.json +11 -8
- package/server/config.js +3 -7
- package/server/index.js +29 -29
- package/server/lib/page-type-util.js +2 -5
- package/server/lib/show-logo.js +3 -3
- package/server/lib/utils.js +6 -11
- package/server/manifest.js +7 -11
- package/server/plugins/renderer/renderer.module.js +38 -100
- package/server/plugins/renderer/responses/index.js +7 -4
- package/server/plugins/renderer/responses/pencil-response.js +4 -32
- package/server/plugins/renderer/responses/raw-response.js +6 -14
- package/server/plugins/renderer/responses/redirect-response.js +1 -4
- package/server/plugins/router/router.module.js +9 -14
- package/server/plugins/theme-assets/theme-assets.module.js +15 -27
package/server/lib/utils.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const uuidRegExp = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-([0-9a-f]{12})';
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
3
|
* Strip domain from the cookies header string
|
|
5
4
|
*
|
|
@@ -13,7 +12,6 @@ function stripDomainFromCookies(cookies) {
|
|
|
13
12
|
.replace(new RegExp('; SameSite=none', 'gi'), ''),
|
|
14
13
|
);
|
|
15
14
|
}
|
|
16
|
-
|
|
17
15
|
/**
|
|
18
16
|
* Strip domain from redirectUrl if it matches the current storeUrl, if not, leave it.
|
|
19
17
|
*
|
|
@@ -25,19 +23,15 @@ function normalizeRedirectUrl(redirectUrl, config) {
|
|
|
25
23
|
if (!redirectUrl || !redirectUrl.startsWith('http')) {
|
|
26
24
|
return redirectUrl; // already stripped, skip
|
|
27
25
|
}
|
|
28
|
-
|
|
29
26
|
const storeHost = new URL(config.normalStoreUrl).host;
|
|
30
27
|
const secureStoreHost = new URL(config.storeUrl).host;
|
|
31
28
|
const redirectUrlObj = new URL(redirectUrl);
|
|
32
|
-
|
|
33
29
|
if (redirectUrlObj.host === storeHost || redirectUrlObj.host === secureStoreHost) {
|
|
34
30
|
// Need to strip
|
|
35
31
|
return redirectUrlObj.pathname + redirectUrlObj.search + redirectUrlObj.hash;
|
|
36
32
|
}
|
|
37
|
-
|
|
38
33
|
return redirectUrl; // Different host, shouldn't strip
|
|
39
34
|
}
|
|
40
|
-
|
|
41
35
|
/**
|
|
42
36
|
* Convert a number to uuid
|
|
43
37
|
*
|
|
@@ -48,7 +42,6 @@ function int2uuid(number) {
|
|
|
48
42
|
const id = `000000000000${number}`.substr(-12);
|
|
49
43
|
return `00000000-0000-0000-0000-${id}`;
|
|
50
44
|
}
|
|
51
|
-
|
|
52
45
|
/**
|
|
53
46
|
* Convert a uuid to int
|
|
54
47
|
*
|
|
@@ -57,15 +50,17 @@ function int2uuid(number) {
|
|
|
57
50
|
*/
|
|
58
51
|
function uuid2int(uuid) {
|
|
59
52
|
const match = uuid.match(new RegExp(uuidRegExp));
|
|
60
|
-
|
|
61
53
|
if (!match) {
|
|
62
54
|
throw new Error(`Not uuid match for ${uuid}`);
|
|
63
55
|
}
|
|
64
|
-
|
|
65
56
|
return match ? parseInt(match[1], 10) : 0;
|
|
66
57
|
}
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
export { stripDomainFromCookies };
|
|
59
|
+
export { normalizeRedirectUrl };
|
|
60
|
+
export { int2uuid };
|
|
61
|
+
export { uuid2int };
|
|
62
|
+
export { uuidRegExp };
|
|
63
|
+
export default {
|
|
69
64
|
stripDomainFromCookies,
|
|
70
65
|
normalizeRedirectUrl,
|
|
71
66
|
int2uuid,
|
package/server/manifest.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import Confidence from 'confidence';
|
|
2
|
+
import * as config from './config.js';
|
|
3
3
|
|
|
4
4
|
const criteria = {
|
|
5
5
|
env: process.env.NODE_ENV,
|
|
6
6
|
};
|
|
7
|
-
|
|
8
7
|
const manifest = {
|
|
9
8
|
$meta: 'Stencil',
|
|
10
9
|
server: {
|
|
@@ -17,15 +16,12 @@ const manifest = {
|
|
|
17
16
|
'@hapi/inert': {},
|
|
18
17
|
'@hapi/h2o2': {},
|
|
19
18
|
// First Party Plugins
|
|
20
|
-
'./plugins/renderer/renderer.module': {},
|
|
21
|
-
'./plugins/router/router.module': {},
|
|
22
|
-
'./plugins/theme-assets/theme-assets.module': {},
|
|
19
|
+
'./plugins/renderer/renderer.module.js': {},
|
|
20
|
+
'./plugins/router/router.module.js': {},
|
|
21
|
+
'./plugins/theme-assets/theme-assets.module.js': {},
|
|
23
22
|
},
|
|
24
23
|
},
|
|
25
24
|
};
|
|
26
|
-
|
|
27
25
|
const store = new Confidence.Store(manifest);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
exports.meta = (key) => store.meta(key, criteria);
|
|
26
|
+
export const get = (key) => store.get(key, criteria);
|
|
27
|
+
export const meta = (key) => store.meta(key, criteria);
|
|
@@ -1,40 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const {
|
|
1
|
+
import { defaultsDeep, omit, isObject, extend, isPlainObject, mapValues, findKey } from 'lodash-es';
|
|
2
|
+
import Boom from '@hapi/boom';
|
|
3
|
+
import cache from 'memory-cache';
|
|
4
|
+
import Crypto from 'crypto';
|
|
5
|
+
import Frontmatter from 'front-matter';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import langAssembler from '../../../lib/lang-assembler.js';
|
|
9
|
+
import { RawResponse, RedirectResponse, PencilResponse } from './responses/index.js';
|
|
10
|
+
import templateAssembler from '../../../lib/template-assembler.js';
|
|
11
|
+
import { int2uuid, stripDomainFromCookies, normalizeRedirectUrl } from '../../lib/utils.js';
|
|
12
|
+
import { readFromStream } from '../../../lib/utils/asyncUtils.js';
|
|
13
|
+
import NetworkUtils from '../../../lib/utils/NetworkUtils.js';
|
|
14
|
+
import contentApiClient from '../../../lib/content-api-client.js';
|
|
15
|
+
import { getPageType } from '../../lib/page-type-util.js';
|
|
16
|
+
import {
|
|
18
17
|
frontmatterRegex,
|
|
19
18
|
getFrontmatterContent,
|
|
20
19
|
interpolateThemeSettings,
|
|
21
|
-
}
|
|
20
|
+
} from '../../../lib/utils/frontmatter.js';
|
|
22
21
|
|
|
23
22
|
const networkUtils = new NetworkUtils();
|
|
24
|
-
|
|
25
23
|
const internals = {
|
|
26
24
|
options: {},
|
|
27
|
-
cacheTTL: 1000 * 15,
|
|
28
|
-
graphQLCacheTTL: 1000 * 300,
|
|
25
|
+
cacheTTL: 1000 * 15,
|
|
26
|
+
graphQLCacheTTL: 1000 * 300,
|
|
29
27
|
validCustomTemplatePageTypes: ['brand', 'category', 'page', 'product'],
|
|
30
28
|
};
|
|
31
|
-
|
|
32
29
|
function register(server, options) {
|
|
33
|
-
internals.options =
|
|
34
|
-
|
|
30
|
+
internals.options = defaultsDeep(options, internals.options);
|
|
35
31
|
server.expose('implementation', internals.implementation);
|
|
36
32
|
}
|
|
37
|
-
|
|
38
33
|
/**
|
|
39
34
|
* Renderer Route Handler
|
|
40
35
|
*
|
|
@@ -43,16 +38,13 @@ function register(server, options) {
|
|
|
43
38
|
*/
|
|
44
39
|
internals.implementation = async (request, h) => {
|
|
45
40
|
let response;
|
|
46
|
-
|
|
47
41
|
try {
|
|
48
42
|
response = await internals.getResponse(request);
|
|
49
43
|
} catch (err) {
|
|
50
44
|
throw Boom.badImplementation(err);
|
|
51
45
|
}
|
|
52
|
-
|
|
53
46
|
return response.respond(request, h);
|
|
54
47
|
};
|
|
55
|
-
|
|
56
48
|
/**
|
|
57
49
|
* Creates a hash
|
|
58
50
|
*
|
|
@@ -62,7 +54,6 @@ internals.implementation = async (request, h) => {
|
|
|
62
54
|
internals.sha1sum = (input) => {
|
|
63
55
|
return Crypto.createHash('sha1').update(JSON.stringify(input)).digest('hex');
|
|
64
56
|
};
|
|
65
|
-
|
|
66
57
|
/**
|
|
67
58
|
* Fetches data from Stapler
|
|
68
59
|
*
|
|
@@ -77,7 +68,6 @@ internals.getResponse = async (request) => {
|
|
|
77
68
|
});
|
|
78
69
|
const withoutPageQuery = new URL(fullUrl.toString());
|
|
79
70
|
withoutPageQuery.searchParams.delete('page');
|
|
80
|
-
|
|
81
71
|
const httpOpts = {
|
|
82
72
|
url: withoutPageQuery.toString(),
|
|
83
73
|
headers: internals.buildReqHeaders({
|
|
@@ -88,20 +78,18 @@ internals.getResponse = async (request) => {
|
|
|
88
78
|
accessToken: internals.options.accessToken,
|
|
89
79
|
data: request.payload,
|
|
90
80
|
method: request.method,
|
|
91
|
-
maxRedirects: 0,
|
|
81
|
+
maxRedirects: 0,
|
|
92
82
|
// If the response is an image it will be parsed wrongly, so we receive a raw data (stream)
|
|
93
83
|
// and perform it manually depending on contentType later
|
|
94
84
|
responseType: 'stream',
|
|
95
85
|
validateStatus: (status) => status >= 200 && status < 500,
|
|
96
86
|
};
|
|
97
|
-
|
|
98
87
|
const responseArgs = {
|
|
99
88
|
httpOpts: { ...httpOpts, url: fullUrl.toString() },
|
|
100
89
|
storeUrlObj,
|
|
101
90
|
};
|
|
102
|
-
|
|
103
91
|
// check request signature and use cache, if available
|
|
104
|
-
const httpOptsSignature =
|
|
92
|
+
const httpOptsSignature = omit(httpOpts.headers, ['cookie']);
|
|
105
93
|
const requestSignature = internals.sha1sum(httpOpts.url) + internals.sha1sum(httpOptsSignature);
|
|
106
94
|
const cachedResponse = cache.get(requestSignature);
|
|
107
95
|
if (cachedResponse && request.method === 'get' && internals.options.useCache) {
|
|
@@ -117,22 +105,18 @@ internals.getResponse = async (request) => {
|
|
|
117
105
|
cache.clear();
|
|
118
106
|
}
|
|
119
107
|
const response = await networkUtils.sendApiRequest(httpOpts);
|
|
120
|
-
|
|
121
108
|
internals.processResHeaders(response.headers);
|
|
122
|
-
|
|
123
109
|
// Redirect
|
|
124
110
|
if (response.status >= 301 && response.status <= 303) {
|
|
125
111
|
return internals.redirect(response, request);
|
|
126
112
|
}
|
|
127
113
|
// Else response is success (2xx), need to handle it further
|
|
128
114
|
// (5xx will be just thrown by axios)
|
|
129
|
-
|
|
130
115
|
const contentType = response.headers['content-type'] || '';
|
|
131
116
|
const isResponseJson = contentType.toLowerCase().includes('application/json');
|
|
132
117
|
const bcAppData = isResponseJson
|
|
133
118
|
? JSON.parse(await readFromStream(response.data))
|
|
134
119
|
: response.data;
|
|
135
|
-
|
|
136
120
|
// cache response
|
|
137
121
|
cache.put(
|
|
138
122
|
requestSignature,
|
|
@@ -144,7 +128,6 @@ internals.getResponse = async (request) => {
|
|
|
144
128
|
);
|
|
145
129
|
return internals.parseResponse(bcAppData, request, response, responseArgs);
|
|
146
130
|
};
|
|
147
|
-
|
|
148
131
|
/**
|
|
149
132
|
* parses the response from bc app
|
|
150
133
|
*
|
|
@@ -156,22 +139,17 @@ internals.getResponse = async (request) => {
|
|
|
156
139
|
*/
|
|
157
140
|
internals.parseResponse = async (bcAppData, request, response, responseArgs) => {
|
|
158
141
|
const { httpOpts, storeUrlObj } = responseArgs;
|
|
159
|
-
|
|
160
142
|
if (typeof bcAppData !== 'object' || !('pencil_response' in bcAppData)) {
|
|
161
143
|
delete response.headers['x-frame-options'];
|
|
162
|
-
|
|
163
144
|
// this is a raw response not emitted by TemplateEngine
|
|
164
145
|
return new RawResponse(bcAppData, response.headers, response.status);
|
|
165
146
|
}
|
|
166
|
-
|
|
167
147
|
const configuration = await request.app.themeConfig.getConfig();
|
|
168
|
-
|
|
169
148
|
// If a remote call, no need to do a second call to get the data,
|
|
170
149
|
// it has already come back
|
|
171
150
|
if (bcAppData.remote) {
|
|
172
151
|
return internals.getPencilResponse(bcAppData, request, response, configuration);
|
|
173
152
|
}
|
|
174
|
-
|
|
175
153
|
httpOpts.headers = internals.buildReqHeaders({
|
|
176
154
|
request,
|
|
177
155
|
stencilOptions: { get_data_only: true },
|
|
@@ -181,47 +159,37 @@ internals.parseResponse = async (bcAppData, request, response, responseArgs) =>
|
|
|
181
159
|
},
|
|
182
160
|
});
|
|
183
161
|
httpOpts.responseType = 'json'; // In the second request we always expect json
|
|
184
|
-
|
|
185
162
|
// create request signature for caching
|
|
186
|
-
const httpOptsSignature = internals.sha1sum(
|
|
163
|
+
const httpOptsSignature = internals.sha1sum(omit(httpOpts.headers, ['cookie']));
|
|
187
164
|
const urlSignature = internals.sha1sum(httpOpts.url);
|
|
188
165
|
const dataRequestSignature = `bcapp:${urlSignature}${httpOptsSignature}`;
|
|
189
166
|
const cachedResponse2 = cache.get(dataRequestSignature);
|
|
190
|
-
|
|
191
167
|
let response2;
|
|
192
168
|
// check request signature and use cache, if available
|
|
193
169
|
if (internals.options.useCache && cachedResponse2) {
|
|
194
170
|
({ response2 } = cachedResponse2);
|
|
195
171
|
} else {
|
|
196
172
|
response2 = await networkUtils.sendApiRequest(httpOpts);
|
|
197
|
-
|
|
198
173
|
internals.processResHeaders(response2.headers);
|
|
199
|
-
|
|
200
174
|
// Response is a redirect
|
|
201
175
|
if (response2.status >= 301 && response2.status <= 303) {
|
|
202
176
|
return internals.redirect(response2, request);
|
|
203
177
|
}
|
|
204
|
-
|
|
205
178
|
if (response2.data && response2.data.status === 500) {
|
|
206
179
|
throw new Error('The BigCommerce server responded with a 500 error');
|
|
207
180
|
}
|
|
208
|
-
|
|
209
181
|
cache.put(dataRequestSignature, { response2 }, internals.cacheTTL);
|
|
210
182
|
}
|
|
211
|
-
|
|
212
183
|
const templateFile = response2.data.template_file;
|
|
213
184
|
const entityId = response2.data.entity_id;
|
|
214
|
-
|
|
215
185
|
const pageType = getPageType(templateFile);
|
|
216
186
|
let regionResponse = [];
|
|
217
|
-
|
|
218
187
|
if (pageType) {
|
|
219
188
|
// create request signature and use cache, if available
|
|
220
189
|
const graphQLUrlSignature = internals.sha1sum(internals.options.storeUrl + '/graphql');
|
|
221
190
|
const graphQLQuerySignature = internals.sha1sum(pageType + entityId);
|
|
222
191
|
const graphQLDataReqSignature = `graphql:${graphQLUrlSignature + graphQLQuerySignature}`;
|
|
223
192
|
const cachedGraphQLResponse = cache.get(graphQLDataReqSignature);
|
|
224
|
-
|
|
225
193
|
if (internals.options.useCache && cachedGraphQLResponse) {
|
|
226
194
|
({ regionResponse } = cachedGraphQLResponse);
|
|
227
195
|
} else {
|
|
@@ -239,19 +207,15 @@ internals.parseResponse = async (bcAppData, request, response, responseArgs) =>
|
|
|
239
207
|
pageType,
|
|
240
208
|
});
|
|
241
209
|
}
|
|
242
|
-
|
|
243
210
|
cache.put(graphQLDataReqSignature, { regionResponse }, internals.graphQLCacheTTL);
|
|
244
211
|
}
|
|
245
212
|
}
|
|
246
|
-
|
|
247
213
|
const formattedRegions = {};
|
|
248
|
-
|
|
249
214
|
if (typeof regionResponse.renderedRegions !== 'undefined') {
|
|
250
215
|
regionResponse.renderedRegions.forEach((region) => {
|
|
251
216
|
formattedRegions[region.name] = region.html;
|
|
252
217
|
});
|
|
253
218
|
}
|
|
254
|
-
|
|
255
219
|
return internals.getPencilResponse(
|
|
256
220
|
response2.data,
|
|
257
221
|
request,
|
|
@@ -260,7 +224,6 @@ internals.parseResponse = async (bcAppData, request, response, responseArgs) =>
|
|
|
260
224
|
formattedRegions,
|
|
261
225
|
);
|
|
262
226
|
};
|
|
263
|
-
|
|
264
227
|
/**
|
|
265
228
|
* Get the resource configuration (front-matter) from the main template
|
|
266
229
|
* or from the header stencil-config for ajax requests
|
|
@@ -273,7 +236,6 @@ internals.getResourceConfig = (data, request, configuration) => {
|
|
|
273
236
|
const missingThemeSettingsRegex = /{{\\s*?theme_settings\\..+?\\s*?}}/g;
|
|
274
237
|
let resourcesConfig = {};
|
|
275
238
|
const templatePath = internals.getTemplatePath(request.path, data);
|
|
276
|
-
|
|
277
239
|
// If the requested template is not an array, we parse the Frontmatter
|
|
278
240
|
// If it is an array, then it's an ajax request using `render_with` with multiple components
|
|
279
241
|
// which don't have Frontmatter and needs to get it's config from the `stencil-config` header.
|
|
@@ -282,7 +244,6 @@ internals.getResourceConfig = (data, request, configuration) => {
|
|
|
282
244
|
internals.getThemeTemplatesPath(),
|
|
283
245
|
templatePath,
|
|
284
246
|
);
|
|
285
|
-
|
|
286
247
|
let frontmatterContent = getFrontmatterContent(rawTemplate);
|
|
287
248
|
if (frontmatterContent !== null) {
|
|
288
249
|
frontmatterContent = interpolateThemeSettings(
|
|
@@ -294,12 +255,11 @@ internals.getResourceConfig = (data, request, configuration) => {
|
|
|
294
255
|
// Replace the frontmatter with the newly interpolated version
|
|
295
256
|
rawTemplate = rawTemplate.replace(frontmatterRegex, frontmatterContent);
|
|
296
257
|
}
|
|
297
|
-
|
|
298
258
|
const frontmatter = Frontmatter(rawTemplate); // Set the config
|
|
299
259
|
resourcesConfig = frontmatter.attributes;
|
|
300
260
|
// Merge the frontmatter config with the global resource config
|
|
301
|
-
if (
|
|
302
|
-
resourcesConfig =
|
|
261
|
+
if (isObject(configuration.resources)) {
|
|
262
|
+
resourcesConfig = extend({}, configuration.resources, resourcesConfig);
|
|
303
263
|
}
|
|
304
264
|
} else if (request.headers['stencil-config']) {
|
|
305
265
|
try {
|
|
@@ -308,10 +268,8 @@ internals.getResourceConfig = (data, request, configuration) => {
|
|
|
308
268
|
resourcesConfig = {};
|
|
309
269
|
}
|
|
310
270
|
}
|
|
311
|
-
|
|
312
271
|
return resourcesConfig;
|
|
313
272
|
};
|
|
314
|
-
|
|
315
273
|
/**
|
|
316
274
|
* Redirects based on the response & request
|
|
317
275
|
*
|
|
@@ -321,17 +279,13 @@ internals.getResourceConfig = (data, request, configuration) => {
|
|
|
321
279
|
*/
|
|
322
280
|
internals.redirect = async (response, request) => {
|
|
323
281
|
const { location } = response.headers;
|
|
324
|
-
|
|
325
282
|
if (!location) {
|
|
326
283
|
throw new Error('StatusCode is set to 30x but there is no location header to redirect to.');
|
|
327
284
|
}
|
|
328
|
-
|
|
329
|
-
response.headers.location = utils.normalizeRedirectUrl(location, request.app);
|
|
330
|
-
|
|
285
|
+
response.headers.location = normalizeRedirectUrl(location, request.app);
|
|
331
286
|
// return a redirect response
|
|
332
287
|
return new RedirectResponse(location, response.headers, response.status);
|
|
333
288
|
};
|
|
334
|
-
|
|
335
289
|
/**
|
|
336
290
|
*
|
|
337
291
|
* @param {string} requestPath
|
|
@@ -342,30 +296,25 @@ internals.getTemplatePath = (requestPath, data) => {
|
|
|
342
296
|
const customLayouts = internals.options.customLayouts || {};
|
|
343
297
|
const pageType = data.page_type;
|
|
344
298
|
let templatePath;
|
|
345
|
-
|
|
346
299
|
if (
|
|
347
300
|
internals.validCustomTemplatePageTypes.includes(pageType) &&
|
|
348
|
-
|
|
301
|
+
isPlainObject(customLayouts[pageType])
|
|
349
302
|
) {
|
|
350
|
-
templatePath =
|
|
303
|
+
templatePath = findKey(customLayouts[pageType], (paths) => {
|
|
351
304
|
// Can be either string or Array, so normalize to Arrays
|
|
352
305
|
const normalizedPaths = typeof paths === 'string' ? [paths] : paths;
|
|
353
|
-
|
|
354
306
|
const matches = normalizedPaths.filter((url) => {
|
|
355
307
|
// remove trailing slashes to compare
|
|
356
308
|
return url.replace(/\/$/, '') === requestPath.replace(/\/$/, '');
|
|
357
309
|
});
|
|
358
|
-
|
|
359
310
|
return matches.length > 0;
|
|
360
311
|
});
|
|
361
|
-
|
|
362
312
|
if (templatePath) {
|
|
363
313
|
templatePath = path.join('pages/custom', pageType, templatePath.replace(/\.html$/, ''));
|
|
364
314
|
}
|
|
365
315
|
}
|
|
366
316
|
return templatePath || data.template_file;
|
|
367
317
|
};
|
|
368
|
-
|
|
369
318
|
function getAcceptLanguageHeader(request) {
|
|
370
319
|
if (
|
|
371
320
|
internals.options.storeSettingsLocale.shopper_language_selection_method ===
|
|
@@ -375,7 +324,6 @@ function getAcceptLanguageHeader(request) {
|
|
|
375
324
|
}
|
|
376
325
|
return request.headers['accept-language'].toLowerCase();
|
|
377
326
|
}
|
|
378
|
-
|
|
379
327
|
/**
|
|
380
328
|
* Creates a new Pencil Response object and returns it.
|
|
381
329
|
*
|
|
@@ -395,13 +343,12 @@ internals.getPencilResponse = (data, request, response, configuration, renderedR
|
|
|
395
343
|
...data.context.settings,
|
|
396
344
|
// change cdn settings to serve local assets
|
|
397
345
|
cdn_url: '',
|
|
398
|
-
theme_version_id:
|
|
399
|
-
theme_config_id:
|
|
346
|
+
theme_version_id: int2uuid(1),
|
|
347
|
+
theme_config_id: int2uuid(request.app.themeConfig.variationIndex + 1),
|
|
400
348
|
theme_session_id: null,
|
|
401
349
|
maintenance: { secure_path: `http://localhost:${internals.options.port}` },
|
|
402
350
|
},
|
|
403
351
|
};
|
|
404
|
-
|
|
405
352
|
return new PencilResponse(
|
|
406
353
|
{
|
|
407
354
|
template_file: internals.getTemplatePath(request.path, data),
|
|
@@ -419,7 +366,6 @@ internals.getPencilResponse = (data, request, response, configuration, renderedR
|
|
|
419
366
|
internals.themeAssembler,
|
|
420
367
|
);
|
|
421
368
|
};
|
|
422
|
-
|
|
423
369
|
/**
|
|
424
370
|
* Get headers from request and return a new object with processed headers
|
|
425
371
|
*
|
|
@@ -441,21 +387,16 @@ internals.buildReqHeaders = ({
|
|
|
441
387
|
const currentOptions = request.headers['stencil-options']
|
|
442
388
|
? JSON.parse(request.headers['stencil-options'])
|
|
443
389
|
: {};
|
|
444
|
-
|
|
445
390
|
const headers = {
|
|
446
391
|
'stencil-options': JSON.stringify({ ...stencilOptions, ...currentOptions }),
|
|
447
392
|
'accept-encoding': 'identity',
|
|
448
393
|
};
|
|
449
|
-
|
|
450
394
|
const config = request.headers['stencil-config'];
|
|
451
|
-
|
|
452
395
|
if ((!config || config === '{}') && stencilConfig) {
|
|
453
396
|
headers['stencil-config'] = JSON.stringify(stencilConfig);
|
|
454
397
|
}
|
|
455
|
-
|
|
456
398
|
return { ...request.headers, ...headers, ...extraHeaders };
|
|
457
399
|
};
|
|
458
|
-
|
|
459
400
|
/**
|
|
460
401
|
* Process headers from Fetch response
|
|
461
402
|
*
|
|
@@ -465,10 +406,9 @@ internals.buildReqHeaders = ({
|
|
|
465
406
|
internals.processResHeaders = (headers) => {
|
|
466
407
|
if (headers && headers['set-cookie']) {
|
|
467
408
|
// eslint-disable-next-line no-param-reassign
|
|
468
|
-
headers['set-cookie'] =
|
|
409
|
+
headers['set-cookie'] = stripDomainFromCookies(headers['set-cookie']);
|
|
469
410
|
}
|
|
470
411
|
};
|
|
471
|
-
|
|
472
412
|
/**
|
|
473
413
|
* Theme assembler interface for paper
|
|
474
414
|
* @type {Object}
|
|
@@ -479,17 +419,14 @@ internals.themeAssembler = {
|
|
|
479
419
|
internals.getThemeTemplatesPath(),
|
|
480
420
|
templatesPath,
|
|
481
421
|
);
|
|
482
|
-
|
|
483
422
|
if (templates[templatesPath]) {
|
|
484
423
|
// Check if the string includes frontmatter configuration and remove it
|
|
485
424
|
const match = templates[templatesPath].match(/---\r?\n[\S\s]*\r?\n---\r?\n([\S\s]*)$/);
|
|
486
|
-
|
|
487
425
|
if (match && match[1]) {
|
|
488
426
|
// eslint-disable-next-line prefer-destructuring
|
|
489
427
|
templates[templatesPath] = match[1];
|
|
490
428
|
}
|
|
491
429
|
}
|
|
492
|
-
|
|
493
430
|
return processor(templates);
|
|
494
431
|
},
|
|
495
432
|
getTranslations: () => {
|
|
@@ -498,18 +435,19 @@ internals.themeAssembler = {
|
|
|
498
435
|
if (err) {
|
|
499
436
|
return reject(err);
|
|
500
437
|
}
|
|
501
|
-
return resolve(
|
|
438
|
+
return resolve(mapValues(translations, (locales) => JSON.parse(locales)));
|
|
502
439
|
});
|
|
503
440
|
});
|
|
504
441
|
},
|
|
505
442
|
};
|
|
506
|
-
|
|
507
443
|
internals.getThemeTemplatesPath = () => {
|
|
508
444
|
return path.join(internals.options.themePath, 'templates');
|
|
509
445
|
};
|
|
510
|
-
|
|
511
|
-
|
|
446
|
+
export const name = 'Renderer';
|
|
447
|
+
export const version = '0.0.1';
|
|
448
|
+
export { register };
|
|
449
|
+
export default {
|
|
512
450
|
register,
|
|
513
|
-
name
|
|
514
|
-
version
|
|
451
|
+
name,
|
|
452
|
+
version,
|
|
515
453
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import PencilResponse from './pencil-response.js';
|
|
2
|
+
import RawResponse from './raw-response.js';
|
|
3
|
+
import RedirectResponse from './redirect-response.js';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
export { PencilResponse };
|
|
6
|
+
export { RawResponse };
|
|
7
|
+
export { RedirectResponse };
|
|
8
|
+
export default {
|
|
6
9
|
PencilResponse,
|
|
7
10
|
RawResponse,
|
|
8
11
|
RedirectResponse,
|