@sitecore-jss/sitecore-jss-nextjs 21.7.0-canary.6 → 21.7.0-canary.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.
Files changed (51) hide show
  1. package/context.d.ts +1 -0
  2. package/context.js +1 -0
  3. package/dist/cjs/components/NextImage.js +2 -10
  4. package/dist/cjs/components/RichText.js +2 -2
  5. package/dist/cjs/context/context.js +83 -0
  6. package/dist/cjs/context/index.js +5 -0
  7. package/dist/cjs/editing/editing-config-middleware.js +49 -0
  8. package/dist/cjs/editing/editing-render-middleware.js +3 -16
  9. package/dist/cjs/editing/feaas-render-middleware.js +87 -0
  10. package/dist/cjs/editing/index.js +5 -1
  11. package/dist/cjs/editing/render-middleware.js +27 -0
  12. package/dist/cjs/graphql/index.js +2 -1
  13. package/dist/cjs/index.js +6 -3
  14. package/dist/cjs/middleware/personalize-middleware.js +33 -32
  15. package/dist/cjs/middleware/redirects-middleware.js +24 -9
  16. package/dist/cjs/revalidate/index.js +5 -0
  17. package/dist/cjs/revalidate/revalidate-middleware.js +216 -0
  18. package/dist/cjs/utils/utils.js +6 -18
  19. package/dist/esm/components/NextImage.js +1 -8
  20. package/dist/esm/components/RichText.js +2 -2
  21. package/dist/esm/context/context.js +79 -0
  22. package/dist/esm/context/index.js +1 -0
  23. package/dist/esm/editing/editing-config-middleware.js +45 -0
  24. package/dist/esm/editing/editing-render-middleware.js +4 -17
  25. package/dist/esm/editing/feaas-render-middleware.js +83 -0
  26. package/dist/esm/editing/index.js +2 -0
  27. package/dist/esm/editing/render-middleware.js +23 -0
  28. package/dist/esm/graphql/index.js +1 -1
  29. package/dist/esm/index.js +4 -3
  30. package/dist/esm/middleware/personalize-middleware.js +34 -33
  31. package/dist/esm/middleware/redirects-middleware.js +24 -9
  32. package/dist/esm/revalidate/index.js +1 -0
  33. package/dist/esm/revalidate/revalidate-middleware.js +212 -0
  34. package/dist/esm/utils/utils.js +6 -15
  35. package/package.json +13 -13
  36. package/revalidate.d.ts +1 -0
  37. package/revalidate.js +1 -0
  38. package/types/components/NextImage.d.ts +1 -2
  39. package/types/context/context.d.ts +116 -0
  40. package/types/context/index.d.ts +1 -0
  41. package/types/editing/editing-config-middleware.d.ts +29 -0
  42. package/types/editing/editing-render-middleware.d.ts +2 -11
  43. package/types/editing/feaas-render-middleware.d.ts +32 -0
  44. package/types/editing/index.d.ts +2 -0
  45. package/types/editing/render-middleware.d.ts +15 -0
  46. package/types/graphql/index.d.ts +1 -1
  47. package/types/index.d.ts +4 -3
  48. package/types/middleware/personalize-middleware.d.ts +20 -15
  49. package/types/revalidate/index.d.ts +1 -0
  50. package/types/revalidate/revalidate-middleware.d.ts +115 -0
  51. package/types/utils/utils.d.ts +1 -0
@@ -0,0 +1,216 @@
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.RevalidateMiddleware = void 0;
13
+ // import { I18NConfig } from 'next/dist/server/config-shared';
14
+ const personalize_1 = require("@sitecore-jss/sitecore-jss/personalize");
15
+ const site_1 = require("@sitecore-jss/sitecore-jss/site");
16
+ const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
17
+ var EntityDefinition;
18
+ (function (EntityDefinition) {
19
+ EntityDefinition["LayoutData"] = "LayoutData";
20
+ EntityDefinition["Item"] = "Item";
21
+ })(EntityDefinition || (EntityDefinition = {}));
22
+ /**
23
+ * Middleware / handler for on-demand ISR (e.g. '/api/revalidate').
24
+ */
25
+ class RevalidateMiddleware {
26
+ constructor(config) {
27
+ this.config = config;
28
+ this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
29
+ // filter out updated paths and language from request.body
30
+ const filteredUpdates = this.getFilteredUpdates(req);
31
+ if (this.isEmpty(filteredUpdates)) {
32
+ // nothing to revalidate
33
+ return res.status(204).json({ message: 'No updates to revalidate' });
34
+ }
35
+ // extract only paths from filtered updates object
36
+ const paths = this.extractPaths(filteredUpdates);
37
+ const pathsToRevalidate = [];
38
+ // when personalization is configured and when both multiSite and personalization are configured
39
+ if (this.config.personalize) {
40
+ const personalizeInfo = yield this.getPersonalizedResults(filteredUpdates);
41
+ if (this.config.multiSite) {
42
+ this.handleMultiSitePersonalization(personalizeInfo, pathsToRevalidate, this.getPathName, this.getSiteName);
43
+ }
44
+ else {
45
+ this.handleNonMultiSitePersonalization(personalizeInfo, pathsToRevalidate, this.getPathName);
46
+ }
47
+ }
48
+ // when only multiSite is configured
49
+ if (this.config.multiSite && !this.config.personalize) {
50
+ const multiSitePaths = paths.map((path) => (0, site_1.getSiteRewrite)(this.getPathName(path), { siteName: this.getSiteName(path) }));
51
+ pathsToRevalidate.push(...multiSitePaths);
52
+ }
53
+ // when both multiSite and personalization are not configured
54
+ if (!this.config.multiSite && !this.config.personalize) {
55
+ const defaultPaths = paths.map((path) => this.getPathName(path));
56
+ pathsToRevalidate.push(...defaultPaths);
57
+ }
58
+ // when other locales are configured besides defaultLocale
59
+ if (!this.isEmpty(filteredUpdates)) {
60
+ const filteredLanguage = [...new Set(filteredUpdates.map(({ language }) => language))].join(',');
61
+ if (this.config.localePrefix) {
62
+ const language = this.config.localePrefix(filteredLanguage);
63
+ if (language) {
64
+ yield Promise.all(pathsToRevalidate.map((path) => res.revalidate(`/${language}` + path)));
65
+ }
66
+ }
67
+ }
68
+ yield Promise.all(pathsToRevalidate.map((path) => res.revalidate(path)));
69
+ sitecore_jss_1.debug.revalidate(`revalidated paths: ${pathsToRevalidate.join(', ')}`);
70
+ });
71
+ this.personalizeService = new personalize_1.GraphQLPersonalizeService({
72
+ clientFactory: config.clientFactory,
73
+ });
74
+ }
75
+ /**
76
+ * Generates a Next.js API route handler that executes a revalidation process.
77
+ * @returns The route handler function for handling Next.js API requests.
78
+ */
79
+ getHandler() {
80
+ return (req, res) => __awaiter(this, void 0, void 0, function* () {
81
+ try {
82
+ yield this.handler(req, res);
83
+ return res.status(200).json({ revalidated: true });
84
+ }
85
+ catch (error) {
86
+ console.log('Error Revalidating:');
87
+ console.log(error);
88
+ return res.status(500).json({ revalidated: false });
89
+ }
90
+ });
91
+ }
92
+ /**
93
+ * Gets personalized results for the updated paths
94
+ * @param {UpdatedPaths[]} filteredUpdates Updated paths
95
+ */
96
+ getPersonalizedResults(filteredUpdates) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ const personalizedResults = [];
99
+ const nonPersonalizedResults = [];
100
+ yield Promise.all(filteredUpdates.map((update) => __awaiter(this, void 0, void 0, function* () {
101
+ const siteName = this.getSiteName(update.path);
102
+ const pathName = this.getPathName(update.path);
103
+ const personalizeInfo = yield this.personalizeService.getPersonalizeInfo(pathName, update.language, siteName);
104
+ if (personalizeInfo && personalizeInfo.variantIds.length > 0) {
105
+ personalizeInfo.variantIds.forEach((variantId) => {
106
+ personalizedResults.push({
107
+ path: update.path,
108
+ variantId,
109
+ });
110
+ });
111
+ }
112
+ else {
113
+ // Collect paths without personalized info
114
+ nonPersonalizedResults.push({
115
+ path: update.path,
116
+ });
117
+ }
118
+ })));
119
+ return {
120
+ personalized: personalizedResults,
121
+ nonPersonalized: nonPersonalizedResults,
122
+ };
123
+ });
124
+ }
125
+ isEmpty(data) {
126
+ return data.length === 0;
127
+ }
128
+ /**
129
+ * Extracts the paths from the updated paths
130
+ * @param {UpdatedPaths[]} filteredUpdates Updated paths
131
+ * @returns {string[]} paths
132
+ */
133
+ extractPaths(filteredUpdates) {
134
+ return filteredUpdates.map((update) => update.path);
135
+ }
136
+ /**
137
+ * Gets the site name from the path name
138
+ * @param {string} pathname Path name
139
+ * @returns {string} site name
140
+ */
141
+ getSiteName(pathname) {
142
+ let siteName = '';
143
+ const path = pathname.endsWith('/') ? pathname : pathname + '/';
144
+ const result = path.match('(.*?)\\/');
145
+ if (result && result[1] !== '') {
146
+ siteName = result[1];
147
+ }
148
+ return siteName;
149
+ }
150
+ /**
151
+ * Gets the path name from the full path
152
+ * @param {string} fullPath Full path
153
+ * @returns {string} path name
154
+ */
155
+ getPathName(fullPath) {
156
+ const pathParts = fullPath.split('/').filter((part) => part !== '');
157
+ if (pathParts.length >= 2) {
158
+ const siteName = `/${pathParts[0]}/`;
159
+ const path = `/${pathParts.slice(1).join('/')}`;
160
+ return path.startsWith(siteName) ? path.slice(siteName.length) : path;
161
+ }
162
+ return '/';
163
+ }
164
+ extractSiteName(path) {
165
+ const siteName = path.split('/')[0];
166
+ return siteName;
167
+ }
168
+ /**
169
+ * Filters out the updated paths and language from the request body
170
+ * @param {NextApiRequest} req Next.js API request
171
+ * @returns {UpdatedPaths[]} updated paths
172
+ */
173
+ getFilteredUpdates(req) {
174
+ var _a, _b;
175
+ if (!((_a = req.body) === null || _a === void 0 ? void 0 : _a.updates) || this.isEmpty(req.body.updates)) {
176
+ return [];
177
+ }
178
+ return (_b = req.body) === null || _b === void 0 ? void 0 : _b.updates.filter((update) => update.entity_definition === EntityDefinition.LayoutData && update.entity_culture).map((update) => {
179
+ if (update.identifier === 'website/') {
180
+ return null;
181
+ }
182
+ return {
183
+ path: update.identifier,
184
+ language: update.entity_culture,
185
+ };
186
+ }).filter(Boolean);
187
+ }
188
+ handleMultiSitePersonalization(personalizeInfo, pathsToRevalidate, getPathName, getSiteName) {
189
+ if (personalizeInfo.personalized.length > 0) {
190
+ const personalizedRewrite = personalizeInfo.personalized.map((info) => {
191
+ return (0, personalize_1.getPersonalizedRewrite)((0, site_1.getSiteRewrite)(getPathName(info.path), { siteName: getSiteName(info.path) }), {
192
+ variantId: info.variantId,
193
+ });
194
+ });
195
+ pathsToRevalidate.push(...personalizedRewrite);
196
+ }
197
+ if (personalizeInfo.nonPersonalized.length > 0) {
198
+ const nonPersonalizedRewrite = personalizeInfo.nonPersonalized.map((info) => {
199
+ return (0, site_1.getSiteRewrite)(getPathName(info.path), {
200
+ siteName: getSiteName(info.path),
201
+ });
202
+ });
203
+ pathsToRevalidate.push(...nonPersonalizedRewrite);
204
+ }
205
+ }
206
+ handleNonMultiSitePersonalization(personalizeInfo, pathsToRevalidate, getPathName) {
207
+ const nonMultiSitePersonalizedRewrite = personalizeInfo.personalized.map((info) => {
208
+ return (0, personalize_1.getPersonalizedRewrite)(getPathName(info.path), { variantId: info.variantId });
209
+ });
210
+ const nonMultiSiteNonPersonalizedRewrite = personalizeInfo.nonPersonalized.map((info) => {
211
+ return this.getPathName(info.path);
212
+ });
213
+ pathsToRevalidate.push(...nonMultiSitePersonalizedRewrite, ...nonMultiSiteNonPersonalizedRewrite);
214
+ }
215
+ }
216
+ exports.RevalidateMiddleware = RevalidateMiddleware;
@@ -1,10 +1,6 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.getJssEditingSecret = exports.handleEditorFastRefresh = exports.getPublicUrl = void 0;
7
- const chalk_1 = __importDefault(require("chalk"));
8
4
  const utils_1 = require("@sitecore-jss/sitecore-jss/utils");
9
5
  /**
10
6
  * Get the publicUrl.
@@ -13,27 +9,19 @@ const utils_1 = require("@sitecore-jss/sitecore-jss/utils");
13
9
  * VERCEL_URL is provided by Vercel in case if we are in Preview deployment (deployment based on the custom branch),
14
10
  * preview deployment has unique url, we don't know exact url.
15
11
  * Similarly, DEPLOY_URL is provided by Netlify and would give us the deploy URL
12
+ * In production non-editing environments it is desirable to use relative urls, so in that case set PUBLIC_URL = ''
16
13
  */
17
14
  const getPublicUrl = () => {
18
- if (process.env.NETLIFY && process.env.DEPLOY_URL)
19
- return process.env.DEPLOY_URL;
20
- if (process.env.VERCEL_URL)
21
- return `https://${process.env.VERCEL_URL}`;
22
15
  let url = process.env.PUBLIC_URL;
23
16
  if (url === undefined) {
24
- console.warn(`${chalk_1.default.yellow.bold('Warning:')} An PUBLIC_URL environment variable is not defined. Falling back to http://localhost:3000.`);
17
+ if (process.env.NETLIFY && process.env.DEPLOY_URL)
18
+ return process.env.DEPLOY_URL;
19
+ if (process.env.VERCEL_URL)
20
+ return `https://${process.env.VERCEL_URL}`;
25
21
  url = 'http://localhost:3000';
26
22
  }
27
- else {
28
- try {
29
- new URL(url);
30
- }
31
- catch (error) {
32
- throw new Error(`The PUBLIC_URL environment variable '${url}' is not a valid URL.`);
33
- }
34
- }
35
23
  // Ensure no trailing slash
36
- return url.toString().replace(/\/$/, '');
24
+ return url.replace(/\/$/, '');
37
25
  };
38
26
  exports.getPublicUrl = getPublicUrl;
39
27
  /**
@@ -14,12 +14,6 @@ import PropTypes from 'prop-types';
14
14
  import React from 'react';
15
15
  import { getEEMarkup, } from '@sitecore-jss/sitecore-jss-react';
16
16
  import Image from 'next/image';
17
- export const sitecoreLoader = ({ src, width }) => {
18
- const [root, paramString] = src.split('?');
19
- const params = new URLSearchParams(paramString);
20
- params.set('mw', width.toString());
21
- return `${root}?${params}`;
22
- };
23
17
  export const NextImage = (_a) => {
24
18
  var { editable, imageParams, field, mediaUrlPrefix, fill, priority } = _a, otherProps = __rest(_a, ["editable", "imageParams", "field", "mediaUrlPrefix", "fill", "priority"]);
25
19
  // next handles src and we use a custom loader,
@@ -55,9 +49,8 @@ export const NextImage = (_a) => {
55
49
  delete imageProps.width;
56
50
  delete imageProps.height;
57
51
  }
58
- const loader = (otherProps.loader ? otherProps.loader : sitecoreLoader);
59
52
  if (attrs) {
60
- return React.createElement(Image, Object.assign({ alt: "", loader: loader }, imageProps));
53
+ return React.createElement(Image, Object.assign({ alt: "" }, imageProps));
61
54
  }
62
55
  return null; // we can't handle the truth
63
56
  };
@@ -27,10 +27,10 @@ export const RichText = (props) => {
27
27
  }
28
28
  }, [hasText]);
29
29
  const routeHandler = (ev) => {
30
- if (!ev.target)
30
+ if (!ev.currentTarget)
31
31
  return;
32
32
  ev.preventDefault();
33
- const pathname = ev.target.href;
33
+ const pathname = ev.currentTarget.href;
34
34
  router.push(pathname, pathname, { locale: false });
35
35
  };
36
36
  const initializeLinks = () => {
@@ -0,0 +1,79 @@
1
+ import { LayoutServicePageState } from '@sitecore-jss/sitecore-jss-react';
2
+ /**
3
+ * Context instance that is used to initialize the application Context and associated Software Development Kits (SDKs).
4
+ */
5
+ export class Context {
6
+ constructor(props) {
7
+ this.props = props;
8
+ /**
9
+ * Indicates whether the Context and SDK(s) have been initialized
10
+ */
11
+ this.isInitialized = false;
12
+ /**
13
+ * Software Development Kits (SDKs) to be initialized
14
+ */
15
+ this.sdks = {};
16
+ /**
17
+ * Promises for the SDKs
18
+ */
19
+ this.sdkPromises = {};
20
+ this.sdkErrors = {};
21
+ /**
22
+ * Retrieves the Software Development Kit (SDK) instance, ensuring it is initialized before returning
23
+ *
24
+ * @param {string} name SDK name
25
+ * @returns initialized SDK
26
+ */
27
+ this.getSDK = (name) => {
28
+ if (!this.sdkPromises[name]) {
29
+ return Promise.reject(`Unknown SDK '${String(name)}'`);
30
+ }
31
+ else {
32
+ return this.sdkPromises[name].then((result) => {
33
+ return ((this.sdkErrors[name] && Promise.reject(this.sdkErrors[name])) || Promise.resolve(result));
34
+ });
35
+ }
36
+ };
37
+ this.sitecoreEdgeUrl = props.sitecoreEdgeUrl;
38
+ this.sitecoreEdgeContextId = props.sitecoreEdgeContextId;
39
+ this.siteName = props.siteName;
40
+ this.pageState = LayoutServicePageState.Normal;
41
+ }
42
+ init(props = {}) {
43
+ // Context and SDKs are initialized only once
44
+ if (this.isInitialized)
45
+ return;
46
+ this.isInitialized = true;
47
+ if (props.siteName) {
48
+ this.siteName = props.siteName;
49
+ }
50
+ if (props.pageState) {
51
+ this.pageState = props.pageState;
52
+ }
53
+ // iterate over the SDKs and initialize them
54
+ for (const sdkName of Object.keys(this.props.sdks)) {
55
+ this.initSDK(sdkName);
56
+ }
57
+ }
58
+ /**
59
+ * Initializes the Software Development Kit (SDK)
60
+ *
61
+ * @param {T} name SDK name
62
+ * @returns {void}
63
+ */
64
+ initSDK(name) {
65
+ this.sdkPromises[name] = new Promise((resolve) => {
66
+ this.props.sdks[name]
67
+ .init(this)
68
+ .then(() => {
69
+ this.sdks[name] = this.props.sdks[name].sdk;
70
+ resolve(this.sdks[name]);
71
+ })
72
+ .catch((e) => {
73
+ // if init rejects, we mark SDK as failed - so getSDK call would reject with a reason
74
+ this.sdkErrors[name] = e;
75
+ resolve(undefined);
76
+ });
77
+ });
78
+ }
79
+ }
@@ -0,0 +1 @@
1
+ export { Context } from './context';
@@ -0,0 +1,45 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { QUERY_PARAM_EDITING_SECRET } from './constants';
11
+ import { getJssEditingSecret } from '../utils/utils';
12
+ import { debug } from '@sitecore-jss/sitecore-jss';
13
+ /**
14
+ * Middleware / handler used in the editing config API route in xmcloud add on (e.g. '/api/editing/config')
15
+ * provides configuration information to determine feature compatibility on Pages side.
16
+ */
17
+ export class EditingConfigMiddleware {
18
+ /**
19
+ * @param {EditingConfigMiddlewareConfig} [config] Editing configuration middleware config
20
+ */
21
+ constructor(config) {
22
+ this.config = config;
23
+ this.handler = (_req, res) => __awaiter(this, void 0, void 0, function* () {
24
+ const secret = _req.query[QUERY_PARAM_EDITING_SECRET];
25
+ if (secret !== getJssEditingSecret()) {
26
+ debug.editing('invalid editing secret - sent "%s" expected "%s"', secret, getJssEditingSecret());
27
+ res.status(401).end('Missing or invalid editing secret');
28
+ }
29
+ const components = Array.isArray(this.config.components)
30
+ ? this.config.components
31
+ : Array.from(this.config.components.keys());
32
+ return res.status(200).json({
33
+ components,
34
+ packages: this.config.metadata.packages,
35
+ });
36
+ });
37
+ }
38
+ /**
39
+ * Gets the Next.js API route handler
40
+ * @returns middleware handler
41
+ */
42
+ getHandler() {
43
+ return this.handler;
44
+ }
45
+ }
@@ -12,33 +12,20 @@ import { AxiosDataFetcher, debug } from '@sitecore-jss/sitecore-jss';
12
12
  import { EDITING_COMPONENT_ID, RenderingType } from '@sitecore-jss/sitecore-jss/layout';
13
13
  import { parse } from 'node-html-parser';
14
14
  import { editingDataService } from './editing-data-service';
15
- import { QUERY_PARAM_EDITING_SECRET, QUERY_PARAM_PROTECTION_BYPASS_SITECORE, QUERY_PARAM_PROTECTION_BYPASS_VERCEL, } from './constants';
15
+ import { QUERY_PARAM_EDITING_SECRET } from './constants';
16
16
  import { getJssEditingSecret } from '../utils/utils';
17
+ import { RenderMiddlewareBase } from './render-middleware';
17
18
  /**
18
19
  * Middleware / handler for use in the editing render Next.js API route (e.g. '/api/editing/render')
19
20
  * which is required for Sitecore editing support.
20
21
  */
21
- export class EditingRenderMiddleware {
22
+ export class EditingRenderMiddleware extends RenderMiddlewareBase {
22
23
  /**
23
24
  * @param {EditingRenderMiddlewareConfig} [config] Editing render middleware config
24
25
  */
25
26
  constructor(config) {
26
27
  var _a, _b, _c, _d;
27
- /**
28
- * Gets query parameters that should be passed along to subsequent requests
29
- * @param query Object of query parameters from incoming URL
30
- * @returns Object of approved query parameters
31
- */
32
- this.getQueryParamsForPropagation = (query) => {
33
- const params = {};
34
- if (query[QUERY_PARAM_PROTECTION_BYPASS_SITECORE]) {
35
- params[QUERY_PARAM_PROTECTION_BYPASS_SITECORE] = query[QUERY_PARAM_PROTECTION_BYPASS_SITECORE];
36
- }
37
- if (query[QUERY_PARAM_PROTECTION_BYPASS_VERCEL]) {
38
- params[QUERY_PARAM_PROTECTION_BYPASS_VERCEL] = query[QUERY_PARAM_PROTECTION_BYPASS_VERCEL];
39
- }
40
- return params;
41
- };
28
+ super();
42
29
  this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
43
30
  var _e, _f;
44
31
  const { method, query, body, headers } = req;
@@ -0,0 +1,83 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { debug } from '@sitecore-jss/sitecore-jss';
11
+ import { QUERY_PARAM_EDITING_SECRET } from './constants';
12
+ import { getJssEditingSecret } from '../utils/utils';
13
+ import { RenderMiddlewareBase } from './render-middleware';
14
+ /**
15
+ * Middleware / handler for use in the feaas render Next.js API route (e.g. '/api/editing/feaas/render')
16
+ * which is required for Sitecore editing support.
17
+ */
18
+ export class FEAASRenderMiddleware extends RenderMiddlewareBase {
19
+ /**
20
+ * @param {EditingRenderMiddlewareConfig} [config] Editing render middleware config
21
+ */
22
+ constructor(config) {
23
+ var _a;
24
+ super();
25
+ this.config = config;
26
+ this.defaultPageUrl = '/feaas/render';
27
+ this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
28
+ const { method, query, headers } = req;
29
+ const startTimestamp = Date.now();
30
+ debug.editing('feaas render middleware start: %o', {
31
+ method,
32
+ query,
33
+ headers,
34
+ });
35
+ if (method !== 'GET') {
36
+ debug.editing('invalid method - sent %s expected GET', method);
37
+ res.setHeader('Allow', 'GET');
38
+ return res.status(405).send(`<html><body>Invalid request method '${method}'</body></html>`);
39
+ }
40
+ // Validate secret
41
+ const secret = query[QUERY_PARAM_EDITING_SECRET];
42
+ if (secret !== getJssEditingSecret()) {
43
+ debug.editing('invalid editing secret - sent "%s" expected "%s"', secret, getJssEditingSecret());
44
+ return res.status(401).send('<html><body>Missing or invalid secret</body></html>');
45
+ }
46
+ try {
47
+ // Get query string parameters to propagate on subsequent requests (e.g. for deployment protection bypass)
48
+ const params = this.getQueryParamsForPropagation(query);
49
+ // Enable Next.js Preview Mode
50
+ res.setPreviewData({});
51
+ const queryParams = new URLSearchParams();
52
+ for (const key in params) {
53
+ if ({}.hasOwnProperty.call(params, key)) {
54
+ queryParams.append(key, params[key]);
55
+ }
56
+ }
57
+ // Pass "feaasSrc" in case a FEAASComponent is being requested
58
+ if (query.feaasSrc) {
59
+ queryParams.append('feaasSrc', query.feaasSrc);
60
+ }
61
+ const redirectUrl = this.pageUrl + (queryParams.toString() ? `?${queryParams.toString()}` : '');
62
+ debug.editing('redirecting to page route %s', redirectUrl);
63
+ debug.editing('feaas render middleware end in %dms', Date.now() - startTimestamp);
64
+ res.redirect(redirectUrl);
65
+ }
66
+ catch (err) {
67
+ const error = err;
68
+ console.info(
69
+ // eslint-disable-next-line quotes
70
+ "Hint: for non-standard server or Next.js route configurations, you may need to override the 'pageUrl' available on the 'FEAASRenderMiddleware' config.");
71
+ res.status(500).send(`<html><body>${error}</body></html>`);
72
+ }
73
+ });
74
+ this.pageUrl = (_a = config === null || config === void 0 ? void 0 : config.pageUrl) !== null && _a !== void 0 ? _a : this.defaultPageUrl;
75
+ }
76
+ /**
77
+ * Gets the Next.js API route handler
78
+ * @returns route handler
79
+ */
80
+ getHandler() {
81
+ return this.handler;
82
+ }
83
+ }
@@ -3,3 +3,5 @@ export { EditingDataMiddleware } from './editing-data-middleware';
3
3
  export { EditingRenderMiddleware, } from './editing-render-middleware';
4
4
  export { BasicEditingDataService, ServerlessEditingDataService, editingDataService, } from './editing-data-service';
5
5
  export { VercelEditingDataCache } from './vercel-editing-data-cache';
6
+ export { FEAASRenderMiddleware } from './feaas-render-middleware';
7
+ export { EditingConfigMiddleware, } from './editing-config-middleware';
@@ -0,0 +1,23 @@
1
+ import { QUERY_PARAM_PROTECTION_BYPASS_SITECORE, QUERY_PARAM_PROTECTION_BYPASS_VERCEL, } from './constants';
2
+ /**
3
+ * Base class for middleware that handles pages and components rendering in Sitecore Editors.
4
+ */
5
+ export class RenderMiddlewareBase {
6
+ constructor() {
7
+ /**
8
+ * Gets query parameters that should be passed along to subsequent requests (e.g. for deployment protection bypass)
9
+ * @param {Object} query Object of query parameters from incoming URL
10
+ * @returns Object of approved query parameters
11
+ */
12
+ this.getQueryParamsForPropagation = (query) => {
13
+ const params = {};
14
+ if (query[QUERY_PARAM_PROTECTION_BYPASS_SITECORE]) {
15
+ params[QUERY_PARAM_PROTECTION_BYPASS_SITECORE] = query[QUERY_PARAM_PROTECTION_BYPASS_SITECORE];
16
+ }
17
+ if (query[QUERY_PARAM_PROTECTION_BYPASS_VERCEL]) {
18
+ params[QUERY_PARAM_PROTECTION_BYPASS_VERCEL] = query[QUERY_PARAM_PROTECTION_BYPASS_VERCEL];
19
+ }
20
+ return params;
21
+ };
22
+ }
23
+ }
@@ -1 +1 @@
1
- export { GraphQLRequestClient, getEdgeProxyContentUrl, } from '@sitecore-jss/sitecore-jss/graphql';
1
+ export { DefaultRetryStrategy, GraphQLRequestClient, getEdgeProxyContentUrl, } from '@sitecore-jss/sitecore-jss/graphql';
package/dist/esm/index.js CHANGED
@@ -20,11 +20,11 @@ const { GraphQLRequestClientDep: GraphQLRequestClient } = {
20
20
  export { GraphQLRequestClient };
21
21
  export { handleEditorFastRefresh, getPublicUrl };
22
22
  export { isEditorActive, resetEditorChromes, resolveUrl, tryParseEnvValue };
23
- export { LayoutServicePageState, GraphQLLayoutService, RestLayoutService, getChildPlaceholder, getFieldValue, RenderingType, EDITING_COMPONENT_PLACEHOLDER, EDITING_COMPONENT_ID, } from '@sitecore-jss/sitecore-jss/layout';
23
+ export { LayoutServicePageState, GraphQLLayoutService, RestLayoutService, getChildPlaceholder, getFieldValue, RenderingType, EDITING_COMPONENT_PLACEHOLDER, EDITING_COMPONENT_ID, getContentStylesheetLink, } from '@sitecore-jss/sitecore-jss/layout';
24
24
  export { mediaApi } from '@sitecore-jss/sitecore-jss/media';
25
25
  export { trackingApi, } from '@sitecore-jss/sitecore-jss/tracking';
26
26
  export { GraphQLDictionaryService, RestDictionaryService, } from '@sitecore-jss/sitecore-jss/i18n';
27
- export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, normalizePersonalizedRewrite, CdpHelper, PosResolver, } from '@sitecore-jss/sitecore-jss/personalize';
27
+ export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, normalizePersonalizedRewrite, CdpHelper, } from '@sitecore-jss/sitecore-jss/personalize';
28
28
  export { ComponentPropsService } from './services/component-props-service';
29
29
  export { DisconnectedSitemapService } from './services/disconnected-sitemap-service';
30
30
  export { GraphQLSitemapService, } from './services/graphql-sitemap-service';
@@ -41,4 +41,5 @@ import * as BYOCWrapper from './components/BYOCWrapper';
41
41
  export { FEaaSWrapper };
42
42
  export { BYOCWrapper };
43
43
  export { ComponentBuilder } from './ComponentBuilder';
44
- export { Image, Text, DateField, EditFrame, FEaaSComponent, fetchFEaaSComponentServerProps, BYOCComponent, getFEAASLibraryStylesheetLinks, File, VisitorIdentification, SitecoreContext, SitecoreContextReactContext, withSitecoreContext, useSitecoreContext, withEditorChromes, withPlaceholder, withDatasourceCheck, } from '@sitecore-jss/sitecore-jss-react';
44
+ export { Context } from './context';
45
+ export { Image, Text, DateField, EditFrame, FEaaSComponent, fetchFEaaSComponentServerProps, BYOCComponent, getFEAASLibraryStylesheetLinks, getComponentLibraryStylesheetLinks, File, VisitorIdentification, SitecoreContext, SitecoreContextReactContext, withSitecoreContext, useSitecoreContext, withEditorChromes, withPlaceholder, withDatasourceCheck, } from '@sitecore-jss/sitecore-jss-react';