@sitecore-jss/sitecore-jss-proxy 22.3.0 → 22.3.1-canary.2

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.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/index.js +19 -447
  3. package/dist/cjs/middleware/editing/config.js +27 -0
  4. package/dist/cjs/middleware/editing/index.js +89 -0
  5. package/dist/cjs/middleware/editing/render.js +103 -0
  6. package/dist/cjs/middleware/headless-ssr-proxy/index.js +450 -0
  7. package/dist/cjs/middleware/healthcheck/index.js +16 -0
  8. package/dist/cjs/middleware/index.js +32 -0
  9. package/dist/cjs/personalize/PersonalizeHelper.js +243 -0
  10. package/dist/cjs/personalize/index.js +5 -0
  11. package/dist/cjs/personalize/test-data/personalizeData.js +86 -0
  12. package/dist/cjs/types/personalize.js +2 -0
  13. package/dist/esm/index.js +4 -441
  14. package/dist/esm/middleware/editing/config.js +23 -0
  15. package/dist/esm/middleware/editing/index.js +84 -0
  16. package/dist/esm/middleware/editing/render.js +98 -0
  17. package/dist/esm/middleware/headless-ssr-proxy/index.js +441 -0
  18. package/dist/esm/middleware/healthcheck/index.js +12 -0
  19. package/dist/esm/middleware/index.js +4 -0
  20. package/dist/esm/personalize/PersonalizeHelper.js +236 -0
  21. package/dist/esm/personalize/index.js +1 -0
  22. package/dist/esm/personalize/test-data/personalizeData.js +82 -0
  23. package/dist/esm/types/personalize.js +1 -0
  24. package/package.json +22 -9
  25. package/types/index.d.ts +4 -21
  26. package/types/middleware/editing/config.d.ts +27 -0
  27. package/types/middleware/editing/index.d.ts +32 -0
  28. package/types/middleware/editing/render.d.ts +42 -0
  29. package/types/{ProxyConfig.d.ts → middleware/headless-ssr-proxy/ProxyConfig.d.ts} +2 -5
  30. package/types/middleware/headless-ssr-proxy/index.d.ts +20 -0
  31. package/types/middleware/healthcheck/index.d.ts +6 -0
  32. package/types/middleware/index.d.ts +3 -0
  33. package/types/personalize/PersonalizeHelper.d.ts +43 -0
  34. package/types/personalize/index.d.ts +2 -0
  35. package/types/personalize/test-data/personalizeData.d.ts +59 -0
  36. package/types/types/AppRenderer.d.ts +35 -0
  37. package/types/types/index.d.ts +3 -0
  38. package/types/types/personalize.d.ts +85 -0
  39. package/types/AppRenderer.d.ts +0 -10
  40. package/types/RenderResponse.d.ts +0 -15
  41. /package/dist/cjs/{ProxyConfig.js → middleware/headless-ssr-proxy/ProxyConfig.js} +0 -0
  42. /package/dist/cjs/{AppRenderer.js → types/AppRenderer.js} +0 -0
  43. /package/dist/cjs/{RouteUrlParser.js → types/RouteUrlParser.js} +0 -0
  44. /package/dist/cjs/{RenderResponse.js → types/index.js} +0 -0
  45. /package/dist/esm/{ProxyConfig.js → middleware/headless-ssr-proxy/ProxyConfig.js} +0 -0
  46. /package/dist/esm/{AppRenderer.js → types/AppRenderer.js} +0 -0
  47. /package/dist/esm/{RouteUrlParser.js → types/RouteUrlParser.js} +0 -0
  48. /package/dist/esm/{RenderResponse.js → types/index.js} +0 -0
  49. /package/types/{RouteUrlParser.d.ts → types/RouteUrlParser.d.ts} +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Sitecore JavaScript Rendering SDK Proxy
2
2
 
3
- This module is provided as a part of Sitecore JavaScript Rendering SDK (JSS). It contains the headless-mode SSR proxy implementation.
3
+ This module is provided as a part of Sitecore JavaScript Rendering SDK (JSS). It provides middlewares, utilities to work in a headless mode.
4
4
 
5
5
  <!---
6
6
  @TODO: Update to next version docs before release
package/dist/cjs/index.js CHANGED
@@ -1,450 +1,22 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
13
15
  };
14
16
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.rewriteRequestPath = exports.removeEmptyAnalyticsCookie = void 0;
16
- const http_proxy_middleware_1 = require("http-proxy-middleware");
17
- const http_status_codes_1 = __importDefault(require("http-status-codes"));
18
- const set_cookie_parser_1 = __importDefault(require("set-cookie-parser"));
19
- const zlib_1 = __importDefault(require("zlib")); // node.js standard lib
20
- const util_1 = require("./util");
21
- // For some reason, every other response returned by Sitecore contains the 'set-cookie' header with the SC_ANALYTICS_GLOBAL_COOKIE value as an empty string.
22
- // This effectively sets the cookie to empty on the client as well, so if a user were to close their browser
23
- // after one of these 'empty value' responses, they would not be tracked as a returning visitor after re-opening their browser.
24
- // To address this, we simply parse the response cookies and if the analytics cookie is present but has an empty value, then we
25
- // remove it from the response header. This means the existing cookie in the browser remains intact.
26
- const removeEmptyAnalyticsCookie = (proxyResponse) => {
27
- const cookies = set_cookie_parser_1.default.parse(proxyResponse.headers['set-cookie']);
28
- if (cookies) {
29
- const analyticsCookieIndex = cookies.findIndex((c) => c.name === 'SC_ANALYTICS_GLOBAL_COOKIE');
30
- if (analyticsCookieIndex !== -1) {
31
- const analyticsCookie = cookies[analyticsCookieIndex];
32
- if (analyticsCookie && analyticsCookie.value === '') {
33
- cookies.splice(analyticsCookieIndex, 1);
34
- /* eslint-disable no-param-reassign */
35
- proxyResponse.headers['set-cookie'] = cookies;
36
- /* eslint-enable no-param-reassign */
37
- }
38
- }
39
- }
40
- };
41
- exports.removeEmptyAnalyticsCookie = removeEmptyAnalyticsCookie;
42
- // inspired by: http://stackoverflow.com/a/22487927/9324
43
- /**
44
- * @param {IncomingMessage} proxyResponse
45
- * @param {IncomingMessage} request
46
- * @param {ServerResponse} serverResponse
47
- * @param {AppRenderer} renderer
48
- * @param {ProxyConfig} config
49
- */
50
- function renderAppToResponse(proxyResponse, request, serverResponse, renderer, config) {
51
- return __awaiter(this, void 0, void 0, function* () {
52
- // monkey-patch FTW?
53
- const originalWriteHead = serverResponse.writeHead;
54
- const originalWrite = serverResponse.write;
55
- const originalEnd = serverResponse.end;
56
- // these lines are necessary and must happen before we do any writing to the response
57
- // otherwise the headers will have already been sent
58
- delete proxyResponse.headers['content-length'];
59
- proxyResponse.headers['content-type'] = 'text/html; charset=utf-8';
60
- // remove IIS server header for security
61
- delete proxyResponse.headers.server;
62
- if (config.setHeaders) {
63
- config.setHeaders(request, serverResponse, proxyResponse);
64
- }
65
- const contentEncoding = proxyResponse.headers['content-encoding'];
66
- if (contentEncoding &&
67
- (contentEncoding.indexOf('gzip') !== -1 || contentEncoding.indexOf('deflate') !== -1)) {
68
- delete proxyResponse.headers['content-encoding'];
69
- }
70
- // we are going to set our own status code if rendering fails
71
- serverResponse.writeHead = () => serverResponse;
72
- // buffer the response body as it is written for later processing
73
- let buf = Buffer.from('');
74
- serverResponse.write = (data, encoding) => {
75
- if (Buffer.isBuffer(data)) {
76
- buf = Buffer.concat([buf, data]); // append raw buffer
77
- }
78
- else {
79
- buf = Buffer.concat([buf, Buffer.from(data, encoding)]); // append string with optional character encoding (default utf8)
80
- }
81
- // sanity check: if the response is huge, bail.
82
- // ...we don't want to let someone bring down the server by filling up all our RAM.
83
- if (buf.length > config.maxResponseSizeBytes) {
84
- throw new Error('Document too large');
85
- }
86
- return true;
87
- };
88
- /**
89
- * Extract layout service data from proxy response
90
- */
91
- function extractLayoutServiceDataFromProxyResponse() {
92
- return __awaiter(this, void 0, void 0, function* () {
93
- if (proxyResponse.statusCode === http_status_codes_1.default.OK ||
94
- proxyResponse.statusCode === http_status_codes_1.default.NOT_FOUND) {
95
- let responseString;
96
- if (contentEncoding &&
97
- (contentEncoding.indexOf('gzip') !== -1 || contentEncoding.indexOf('deflate') !== -1)) {
98
- responseString = new Promise((resolve, reject) => {
99
- if (config.debug) {
100
- console.log('Layout service response is compressed; decompressing.');
101
- }
102
- zlib_1.default.unzip(buf, (error, result) => {
103
- if (error) {
104
- reject(error);
105
- }
106
- if (result) {
107
- resolve(result.toString('utf-8'));
108
- }
109
- });
110
- });
111
- }
112
- else {
113
- responseString = Promise.resolve(buf.toString('utf-8'));
114
- }
115
- return responseString.then(util_1.tryParseJson);
116
- }
117
- return Promise.resolve(null);
118
- });
119
- }
120
- /**
121
- * function replies with HTTP 500 when an error occurs
122
- * @param {Error} error
123
- */
124
- function replyWithError(error) {
125
- return __awaiter(this, void 0, void 0, function* () {
126
- console.error(error);
127
- let errorResponse = {
128
- statusCode: proxyResponse.statusCode || http_status_codes_1.default.INTERNAL_SERVER_ERROR,
129
- content: proxyResponse.statusMessage || 'Internal Server Error',
130
- headers: {},
131
- };
132
- if (config.onError) {
133
- const onError = yield config.onError(error, proxyResponse);
134
- errorResponse = Object.assign(Object.assign({}, errorResponse), onError);
135
- }
136
- completeProxyResponse(Buffer.from(errorResponse.content), errorResponse.statusCode, errorResponse.headers);
137
- });
138
- }
139
- // callback handles the result of server-side rendering
140
- /**
141
- * @param {Error | null} error
142
- * @param {RenderResponse} result
143
- */
144
- function handleRenderingResult(error, result) {
145
- return __awaiter(this, void 0, void 0, function* () {
146
- if (!error && !result) {
147
- return replyWithError(new Error('Render function did not return a result or an error!'));
148
- }
149
- if (error) {
150
- return replyWithError(error);
151
- }
152
- if (!result) {
153
- // should not occur, but makes TS happy
154
- return replyWithError(new Error('Render function result did not return a result.'));
155
- }
156
- if (!result.html) {
157
- return replyWithError(new Error('Render function result was returned but html property was falsy.'));
158
- }
159
- if (config.transformSSRContent) {
160
- result.html = yield config.transformSSRContent(result, request, serverResponse);
161
- }
162
- // we have to convert back to a buffer so that we can get the *byte count* (rather than character count) of the body
163
- let content = Buffer.from(result.html);
164
- // setting the content-length header is not absolutely necessary, but is recommended
165
- proxyResponse.headers['content-length'] = content.length.toString(10);
166
- // if original request was a HEAD, we should not return a response body
167
- if (request.method === 'HEAD') {
168
- if (config.debug) {
169
- console.log('DEBUG: Original request method was HEAD, clearing response body');
170
- }
171
- content = Buffer.from([]);
172
- }
173
- if (result.redirect) {
174
- if (!result.status) {
175
- result.status = 302;
176
- }
177
- proxyResponse.headers.location = result.redirect;
178
- }
179
- const finalStatusCode = result.status || proxyResponse.statusCode || http_status_codes_1.default.OK;
180
- if (config.debug) {
181
- console.log('DEBUG: FINAL response headers for client', JSON.stringify(proxyResponse.headers, null, 2));
182
- console.log('DEBUG: FINAL status code for client', finalStatusCode);
183
- }
184
- completeProxyResponse(content, finalStatusCode);
185
- });
186
- }
187
- /**
188
- * @param {Buffer | null} content
189
- * @param {number} statusCode
190
- * @param {IncomingHttpHeaders} [headers]
191
- */
192
- function completeProxyResponse(content, statusCode, headers) {
193
- if (!headers) {
194
- headers = proxyResponse.headers;
195
- }
196
- originalWriteHead.apply(serverResponse, [statusCode, headers]);
197
- if (content)
198
- originalWrite.call(serverResponse, content);
199
- originalEnd.call(serverResponse);
200
- }
201
- /**
202
- * @param {object} layoutServiceData
203
- */
204
- function createViewBag(layoutServiceData) {
205
- return __awaiter(this, void 0, void 0, function* () {
206
- let viewBag = {
207
- statusCode: proxyResponse.statusCode,
208
- dictionary: {},
209
- };
210
- if (config.createViewBag) {
211
- const customViewBag = yield config.createViewBag(request, serverResponse, proxyResponse, layoutServiceData);
212
- viewBag = Object.assign(Object.assign({}, viewBag), customViewBag);
213
- }
214
- return viewBag;
215
- });
216
- }
217
- // as the response is ending, we parse the current response body which is JSON, then
218
- // render the app using that JSON, but return HTML to the final response.
219
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
220
- // @ts-ignore
221
- serverResponse.end = () => __awaiter(this, void 0, void 0, function* () {
222
- try {
223
- const layoutServiceData = yield extractLayoutServiceDataFromProxyResponse();
224
- const viewBag = yield createViewBag(layoutServiceData);
225
- if (!layoutServiceData) {
226
- throw new Error(`Received invalid response ${proxyResponse.statusCode} ${proxyResponse.statusMessage}`);
227
- }
228
- return renderer(handleRenderingResult,
229
- // originalUrl not defined in `http-proxy-middleware` types but it exists
230
- request.originalUrl, layoutServiceData, viewBag);
231
- }
232
- catch (error) {
233
- return replyWithError(error);
234
- }
235
- });
236
- });
237
- }
238
- /**
239
- * @param {IncomingMessage} proxyResponse
240
- * @param {Request} request
241
- * @param {Response} serverResponse
242
- * @param {AppRenderer} renderer
243
- * @param {ProxyConfig} config
244
- */
245
- function handleProxyResponse(proxyResponse, request, serverResponse, renderer, config) {
246
- (0, exports.removeEmptyAnalyticsCookie)(proxyResponse);
247
- if (config.debug) {
248
- console.log('DEBUG: request url', request.url);
249
- console.log('DEBUG: request query', request.query);
250
- console.log('DEBUG: request original url', request.originalUrl);
251
- console.log('DEBUG: proxied request response code', proxyResponse.statusCode);
252
- console.log('DEBUG: RAW request headers', JSON.stringify(request.headers, null, 2));
253
- console.log('DEBUG: RAW headers from the proxied response', JSON.stringify(proxyResponse.headers, null, 2));
254
- }
255
- // if the request URL contains any of the excluded rewrite routes, we assume the response does not need to be server rendered.
256
- // instead, the response should just be relayed as usual.
257
- if (isUrlIgnored(request.originalUrl, config, true)) {
258
- return Promise.resolve(undefined);
259
- }
260
- // your first thought might be: why do we need to render the app here? why not just pass the JSON response to another piece of middleware that will render the app?
261
- // the answer: the proxy middleware ends the response and does not "chain"
262
- return renderAppToResponse(proxyResponse, request, serverResponse, renderer, config);
263
- }
264
- /**
265
- * @param {string} reqPath
266
- * @param {Request} req
267
- * @param {ProxyConfig} config
268
- * @param {RouteUrlParser} parseRouteUrl
269
- */
270
- function rewriteRequestPath(reqPath, req, config, parseRouteUrl) {
271
- // the path comes in URL-encoded by default,
272
- // but we don't want that because...
273
- // 1. We need to URL-encode it before we send it out to the Layout Service, if it matches a route
274
- // 2. We don't want to force people to URL-encode ignored routes, etc (just use spaces instead of %20, etc)
275
- const decodedReqPath = decodeURIComponent(reqPath);
276
- // if the request URL contains a path/route that should not be re-written, then just pass it along as-is
277
- if (isUrlIgnored(reqPath, config)) {
278
- // we do not return the decoded URL because we're using it verbatim - should be encoded.
279
- return reqPath;
280
- }
281
- // if the request URL doesn't contain the layout service controller path, assume we need to rewrite the request URL so that it does
282
- // if this seems redundant, it is. the config.pathRewriteExcludeRoutes should contain the layout service path, but can't always assume that it will...
283
- if (decodedReqPath.indexOf(config.layoutServiceRoute) !== -1) {
284
- return reqPath;
285
- }
286
- let finalReqPath = decodedReqPath;
287
- const qsIndex = finalReqPath.indexOf('?');
288
- let qs = '';
289
- if (qsIndex > -1 || Object.keys(req.query).length) {
290
- qs = (0, util_1.buildQueryString)(req.query);
291
- // Splice qs part when url contains that
292
- if (qsIndex > -1)
293
- finalReqPath = finalReqPath.slice(0, qsIndex);
294
- }
295
- if (config.qsParams) {
296
- if (qs) {
297
- qs += '&';
298
- }
299
- qs += `${config.qsParams}`;
300
- }
301
- let lang;
302
- if (parseRouteUrl) {
303
- if (config.debug) {
304
- console.log(`DEBUG: Parsing route URL using ${decodedReqPath} URL...`);
305
- }
306
- const routeParams = parseRouteUrl(finalReqPath);
307
- if (routeParams) {
308
- if (routeParams.sitecoreRoute) {
309
- finalReqPath = routeParams.sitecoreRoute;
310
- }
311
- else {
312
- finalReqPath = '/';
313
- }
314
- if (!finalReqPath.startsWith('/')) {
315
- finalReqPath = `/${finalReqPath}`;
316
- }
317
- lang = routeParams.lang;
318
- if (routeParams.qsParams) {
319
- qs += `&${routeParams.qsParams}`;
320
- }
321
- if (config.debug) {
322
- console.log('DEBUG: parseRouteUrl() result', routeParams);
323
- }
324
- }
325
- }
326
- let path = `${config.layoutServiceRoute}?item=${encodeURIComponent(finalReqPath)}&sc_apikey=${config.apiKey}`;
327
- if (lang) {
328
- path = `${path}&sc_lang=${lang}`;
329
- }
330
- if (qs) {
331
- path = `${path}&${qs}`;
332
- }
333
- return path;
334
- }
335
- exports.rewriteRequestPath = rewriteRequestPath;
336
- /**
337
- * @param {string} originalUrl
338
- * @param {ProxyConfig} config
339
- * @param {boolean} noDebug
340
- */
341
- function isUrlIgnored(originalUrl, config, noDebug = false) {
342
- if (config.pathRewriteExcludePredicate && config.pathRewriteExcludeRoutes) {
343
- console.error('ERROR: pathRewriteExcludePredicate and pathRewriteExcludeRoutes were both provided in config. Provide only one.');
344
- process.exit(1);
345
- }
346
- let result = null;
347
- if (config.pathRewriteExcludeRoutes) {
348
- const matchRoute = decodeURIComponent(originalUrl).toUpperCase();
349
- result = config.pathRewriteExcludeRoutes.find((excludedRoute) => excludedRoute.length > 0 && matchRoute.startsWith(excludedRoute));
350
- if (!noDebug && config.debug) {
351
- if (!result) {
352
- console.log(`DEBUG: URL ${originalUrl} did not match the proxy exclude list, and will be treated as a layout service route to render. Excludes:`, config.pathRewriteExcludeRoutes);
353
- }
354
- else {
355
- console.log(`DEBUG: URL ${originalUrl} matched the proxy exclude list and will be served verbatim as received. Excludes: `, config.pathRewriteExcludeRoutes);
356
- }
357
- }
358
- return result ? true : false;
359
- }
360
- if (config.pathRewriteExcludePredicate) {
361
- result = config.pathRewriteExcludePredicate(originalUrl);
362
- if (!noDebug && config.debug) {
363
- if (!result) {
364
- console.log(`DEBUG: URL ${originalUrl} did not match the proxy exclude function, and will be treated as a layout service route to render.`);
365
- }
366
- else {
367
- console.log(`DEBUG: URL ${originalUrl} matched the proxy exclude function and will be served verbatim as received.`);
368
- }
369
- }
370
- return result;
371
- }
372
- return false;
373
- }
374
- /**
375
- * @param {ClientRequest} proxyReq
376
- * @param {Request} req
377
- * @param {Response} res
378
- * @param {ServerOptions} options
379
- * @param {ProxyConfig} config
380
- * @param {Function} customOnProxyReq
381
- */
382
- function handleProxyRequest(proxyReq, req, res, options, config, customOnProxyReq) {
383
- if (!isUrlIgnored(req.originalUrl, config, true)) {
384
- // In case 'followRedirects' is enabled, and before the proxy was initialized we had set 'originalMethod'
385
- // now we need to set req.method back to original one, since proxyReq is already initialized.
386
- // See more info in 'preProxyHandler'
387
- if (options.followRedirects && req.originalMethod === 'HEAD') {
388
- req.method = req.originalMethod;
389
- delete req.originalMethod;
390
- if (config.debug) {
391
- console.log('DEBUG: Rewriting HEAD request to GET to create accurate headers');
392
- }
393
- }
394
- else if (proxyReq.method === 'HEAD') {
395
- if (config.debug) {
396
- console.log('DEBUG: Rewriting HEAD request to GET to create accurate headers');
397
- }
398
- // if a HEAD request, we still need to issue a GET so we can return accurate headers
399
- proxyReq.method = 'GET';
400
- }
401
- }
402
- // invoke custom onProxyReq
403
- if (customOnProxyReq) {
404
- customOnProxyReq(proxyReq, req, res, options);
405
- }
406
- }
407
- /**
408
- * @param {AppRenderer} renderer
409
- * @param {ProxyConfig} config
410
- * @param {RouteUrlParser} parseRouteUrl
411
- */
412
- function createOptions(renderer, config, parseRouteUrl) {
413
- var _a;
414
- if (!config.maxResponseSizeBytes) {
415
- config.maxResponseSizeBytes = 10 * 1024 * 1024;
416
- }
417
- // ensure all excludes are case insensitive
418
- if (config.pathRewriteExcludeRoutes && Array.isArray(config.pathRewriteExcludeRoutes)) {
419
- config.pathRewriteExcludeRoutes = config.pathRewriteExcludeRoutes.map((exclude) => exclude.toUpperCase());
420
- }
421
- if (config.debug) {
422
- console.log('DEBUG: Final proxy config', config);
423
- }
424
- const customOnProxyReq = (_a = config.proxyOptions) === null || _a === void 0 ? void 0 : _a.onProxyReq;
425
- return Object.assign(Object.assign({}, config.proxyOptions), { target: config.apiHost, changeOrigin: true, ws: config.ws || false, pathRewrite: (reqPath, req) => rewriteRequestPath(reqPath, req, config, parseRouteUrl), logLevel: config.debug ? 'debug' : 'info', onProxyReq: (proxyReq, req, res, options) => handleProxyRequest(proxyReq, req, res, options, config, customOnProxyReq), onProxyRes: (proxyRes, req, res) => handleProxyResponse(proxyRes, req, res, renderer, config) });
426
- }
427
- /**
428
- * @param {AppRenderer} renderer
429
- * @param {ProxyConfig} config
430
- * @param {RouteUrlParser} parseRouteUrl
431
- */
432
- function scProxy(renderer, config, parseRouteUrl) {
433
- const options = createOptions(renderer, config, parseRouteUrl);
434
- const preProxyHandler = (req, _res, next) => {
435
- // When 'followRedirects' is enabled, 'onProxyReq' is executed after 'proxyReq' is initialized based on original 'req'
436
- // and there are no public properties/methods to modify Redirectable 'proxyReq'.
437
- // so, we need to set 'HEAD' req as 'GET' before the proxy is initialized.
438
- // During the 'onProxyReq' event we will set 'req.method' back as 'HEAD'.
439
- // if a HEAD request, we need to issue a GET so we can return accurate headers
440
- if (req.method === 'HEAD' &&
441
- options.followRedirects &&
442
- !isUrlIgnored(req.originalUrl, config, true)) {
443
- req.method = 'GET';
444
- req.originalMethod = 'HEAD';
445
- }
446
- next();
447
- };
448
- return [preProxyHandler, (0, http_proxy_middleware_1.createProxyMiddleware)(options)];
449
- }
450
- exports.default = scProxy;
17
+ exports.GRAPHQL_LAYOUT_QUERY_NAME = void 0;
18
+ __exportStar(require("./middleware"), exports);
19
+ __exportStar(require("./types"), exports);
20
+ __exportStar(require("./personalize"), exports);
21
+ var layout_1 = require("@sitecore-jss/sitecore-jss/layout");
22
+ Object.defineProperty(exports, "GRAPHQL_LAYOUT_QUERY_NAME", { enumerable: true, get: function () { return layout_1.GRAPHQL_LAYOUT_QUERY_NAME; } });
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.editingConfigMiddleware = void 0;
4
+ const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
5
+ const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
6
+ /**
7
+ * Middleware to handle editing config requests
8
+ * @param {EditingConfigEndpointOptions} config Configuration for the endpoint
9
+ * @returns {RequestHandler} Middleware function
10
+ */
11
+ const editingConfigMiddleware = (config) => (_req, res) => {
12
+ sitecore_jss_1.debug.editing('editing config middleware start');
13
+ const startTimestamp = Date.now();
14
+ const components = Array.isArray(config.components)
15
+ ? config.components
16
+ : Array.from(config.components.keys());
17
+ sitecore_jss_1.debug.editing('editing config middleware end in %dms: %o', Date.now() - startTimestamp, {
18
+ components,
19
+ packages: config.metadata.packages,
20
+ });
21
+ res.status(200).json({
22
+ components,
23
+ packages: config.metadata.packages,
24
+ editMode: layout_1.EditMode.Metadata,
25
+ });
26
+ };
27
+ exports.editingConfigMiddleware = editingConfigMiddleware;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.editingRouter = exports.editingMiddleware = void 0;
13
+ const express_1 = require("express");
14
+ const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
15
+ const editing_1 = require("@sitecore-jss/sitecore-jss/editing");
16
+ const utils_1 = require("@sitecore-jss/sitecore-jss/utils");
17
+ const config_1 = require("./config");
18
+ const render_1 = require("./render");
19
+ /**
20
+ * Default endpoints for editing requests
21
+ */
22
+ const ENDPOINTS = {
23
+ CONFIG: '/config',
24
+ RENDER: '/render',
25
+ };
26
+ /**
27
+ * Middleware to handle editing requests
28
+ * @param {Request} req Request
29
+ * @param {Response} res Response
30
+ * @param {NextFunction} next Next function
31
+ */
32
+ const editingMiddleware = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
33
+ var _a;
34
+ const providedSecret = req.query[editing_1.QUERY_PARAM_EDITING_SECRET];
35
+ const secret = process.env.JSS_EDITING_SECRET;
36
+ sitecore_jss_1.debug.editing('editing middleware start: %o', {
37
+ path: req.originalUrl,
38
+ method: req.method,
39
+ query: req.query,
40
+ headers: req.headers,
41
+ });
42
+ if (!(0, utils_1.enforceCors)(req, res, editing_1.EDITING_ALLOWED_ORIGINS)) {
43
+ sitecore_jss_1.debug.editing('invalid origin host - set allowed origins in JSS_ALLOWED_ORIGINS environment variable');
44
+ return res.status(401).send(`Requests from origin ${(_a = req.headers) === null || _a === void 0 ? void 0 : _a.origin} are not allowed`);
45
+ }
46
+ if (!secret) {
47
+ sitecore_jss_1.debug.editing('missing editing secret - set JSS_EDITING_SECRET environment variable');
48
+ return res
49
+ .status(401)
50
+ .send('Missing editing secret - set JSS_EDITING_SECRET environment variable');
51
+ }
52
+ if (secret !== providedSecret) {
53
+ sitecore_jss_1.debug.editing('invalid editing secret - sent "%s" expected "%s"', providedSecret, secret);
54
+ return res.status(401).send('Missing or invalid secret');
55
+ }
56
+ if (req.method === 'OPTIONS') {
57
+ sitecore_jss_1.debug.editing('preflight request');
58
+ // CORS headers are set by enforceCors
59
+ return res.status(204).send();
60
+ }
61
+ return next();
62
+ });
63
+ exports.editingMiddleware = editingMiddleware;
64
+ /**
65
+ * Middleware to handle invalid method or path
66
+ * @param {Request} req Request
67
+ * @param {Response} res Response
68
+ */
69
+ const editingNotFoundMiddleware = (req, res) => {
70
+ sitecore_jss_1.debug.editing('invalid method or path - sent %s %s', req.method, req.originalUrl);
71
+ return res.status(405).send(`Invalid request method or path ${req.method} ${req.originalUrl}`);
72
+ };
73
+ /**
74
+ * Creates a router for editing requests.
75
+ * Supports the following routes:
76
+ * - <routerPath>/render (GET) - renders a route
77
+ * - <routerPath>/config (GET) - returns the current application configuration
78
+ * @param {EditingRouterConfig} options Editing router configuration
79
+ * @returns {Router} Editing router
80
+ */
81
+ const editingRouter = (options) => {
82
+ const router = (0, express_1.Router)();
83
+ router.use(exports.editingMiddleware);
84
+ router.get(options.config.path || ENDPOINTS.CONFIG, (0, config_1.editingConfigMiddleware)(options.config));
85
+ router.get(options.render.path || ENDPOINTS.RENDER, (0, render_1.editingRenderMiddleware)(options.render));
86
+ router.use(editingNotFoundMiddleware);
87
+ return router;
88
+ };
89
+ exports.editingRouter = editingRouter;