@sitecore-jss/sitecore-jss-nextjs 22.1.0-canary.9 → 22.2.0-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 (50) hide show
  1. package/dist/cjs/components/Link.js +7 -3
  2. package/dist/cjs/components/NextImage.js +10 -5
  3. package/dist/cjs/components/RichText.js +2 -2
  4. package/dist/cjs/editing/constants.js +12 -3
  5. package/dist/cjs/editing/editing-config-middleware.js +8 -0
  6. package/dist/cjs/editing/editing-data-middleware.js +6 -0
  7. package/dist/cjs/editing/editing-render-middleware.js +229 -103
  8. package/dist/cjs/editing/feaas-render-middleware.js +8 -0
  9. package/dist/cjs/editing/index.js +4 -1
  10. package/dist/cjs/editing/render-middleware.js +18 -4
  11. package/dist/cjs/index.js +9 -7
  12. package/dist/cjs/middleware/middleware.js +12 -0
  13. package/dist/cjs/middleware/personalize-middleware.js +85 -25
  14. package/dist/cjs/services/base-graphql-sitemap-service.js +5 -4
  15. package/dist/cjs/utils/index.js +4 -3
  16. package/dist/cjs/utils/utils.js +3 -3
  17. package/dist/esm/components/Link.js +7 -3
  18. package/dist/esm/components/NextImage.js +11 -5
  19. package/dist/esm/components/RichText.js +2 -2
  20. package/dist/esm/editing/constants.js +11 -2
  21. package/dist/esm/editing/editing-config-middleware.js +9 -1
  22. package/dist/esm/editing/editing-data-middleware.js +7 -1
  23. package/dist/esm/editing/editing-render-middleware.js +227 -103
  24. package/dist/esm/editing/feaas-render-middleware.js +9 -1
  25. package/dist/esm/editing/index.js +2 -1
  26. package/dist/esm/editing/render-middleware.js +19 -5
  27. package/dist/esm/index.js +3 -4
  28. package/dist/esm/middleware/middleware.js +12 -0
  29. package/dist/esm/middleware/personalize-middleware.js +86 -26
  30. package/dist/esm/services/base-graphql-sitemap-service.js +5 -4
  31. package/dist/esm/utils/index.js +2 -1
  32. package/dist/esm/utils/utils.js +1 -1
  33. package/package.json +10 -11
  34. package/types/ComponentBuilder.d.ts +3 -5
  35. package/types/components/Placeholder.d.ts +7 -2
  36. package/types/components/RichText.d.ts +6 -0
  37. package/types/editing/constants.d.ts +11 -2
  38. package/types/editing/editing-config-middleware.d.ts +7 -0
  39. package/types/editing/editing-data-service.d.ts +1 -0
  40. package/types/editing/editing-render-middleware.d.ts +111 -23
  41. package/types/editing/index.d.ts +2 -1
  42. package/types/editing/render-middleware.d.ts +9 -0
  43. package/types/index.d.ts +3 -4
  44. package/types/middleware/middleware.d.ts +6 -0
  45. package/types/middleware/personalize-middleware.d.ts +22 -2
  46. package/types/services/base-graphql-sitemap-service.d.ts +3 -2
  47. package/types/utils/index.d.ts +2 -1
  48. package/dist/cjs/components/EditingComponentPlaceholder.js +0 -12
  49. package/dist/esm/components/EditingComponentPlaceholder.js +0 -5
  50. package/types/components/EditingComponentPlaceholder.d.ts +0 -4
package/dist/cjs/index.js CHANGED
@@ -23,8 +23,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.DateField = exports.Text = exports.Image = exports.Context = exports.ComponentBuilder = exports.BYOCWrapper = exports.FEaaSWrapper = exports.NextImage = exports.EditingComponentPlaceholder = exports.Placeholder = exports.RichText = exports.Link = exports.useComponentProps = exports.ComponentPropsContext = exports.ComponentPropsReactContext = exports.normalizeSiteRewrite = exports.getSiteRewriteData = exports.getSiteRewrite = exports.GraphQLSiteInfoService = exports.SiteResolver = exports.GraphQLRobotsService = exports.GraphQLErrorPagesService = exports.GraphQLSitemapXmlService = exports.MultisiteGraphQLSitemapService = exports.GraphQLSitemapService = exports.DisconnectedSitemapService = exports.ComponentPropsService = exports.CdpHelper = exports.normalizePersonalizedRewrite = exports.getPersonalizedRewriteData = exports.getPersonalizedRewrite = exports.personalizeLayout = exports.RestDictionaryService = exports.GraphQLDictionaryService = exports.trackingApi = exports.mediaApi = exports.getContentStylesheetLink = exports.EDITING_COMPONENT_ID = exports.EDITING_COMPONENT_PLACEHOLDER = exports.RenderingType = exports.getFieldValue = exports.getChildPlaceholder = exports.RestLayoutService = exports.GraphQLLayoutService = exports.LayoutServicePageState = exports.debug = exports.enableDebug = exports.NativeDataFetcher = exports.AxiosDataFetcher = exports.constants = void 0;
27
- exports.withDatasourceCheck = exports.withPlaceholder = exports.withEditorChromes = exports.useSitecoreContext = exports.withSitecoreContext = exports.SitecoreContextReactContext = exports.SitecoreContext = exports.VisitorIdentification = exports.File = exports.getComponentLibraryStylesheetLinks = exports.BYOCComponent = exports.fetchFEaaSComponentServerProps = exports.FEaaSComponent = exports.EditFrame = void 0;
26
+ exports.FEaaSComponent = exports.EditFrame = exports.DateField = exports.Text = exports.Image = exports.Context = exports.ComponentBuilder = exports.BYOCWrapper = exports.FEaaSWrapper = exports.NextImage = exports.Placeholder = exports.RichText = exports.Link = exports.useComponentProps = exports.ComponentPropsContext = exports.ComponentPropsReactContext = exports.normalizeSiteRewrite = exports.getSiteRewriteData = exports.getSiteRewrite = exports.GraphQLSiteInfoService = exports.SiteResolver = exports.GraphQLRobotsService = exports.GraphQLErrorPagesService = exports.GraphQLSitemapXmlService = exports.MultisiteGraphQLSitemapService = exports.GraphQLSitemapService = exports.DisconnectedSitemapService = exports.ComponentPropsService = exports.CdpHelper = exports.normalizePersonalizedRewrite = exports.getGroomedVariantIds = exports.getPersonalizedRewriteData = exports.getPersonalizedRewrite = exports.personalizeLayout = exports.RestDictionaryService = exports.GraphQLDictionaryService = exports.trackingApi = exports.mediaApi = exports.EditMode = exports.getContentStylesheetLink = exports.getFieldValue = exports.getChildPlaceholder = exports.RestLayoutService = exports.GraphQLLayoutService = exports.LayoutServicePageState = exports.debug = exports.enableDebug = exports.NativeDataFetcher = exports.AxiosDataFetcher = exports.constants = void 0;
27
+ exports.EditingScripts = exports.withEmptyFieldEditingComponent = exports.withFieldMetadata = exports.withDatasourceCheck = exports.withPlaceholder = exports.withEditorChromes = exports.useSitecoreContext = exports.withSitecoreContext = exports.SitecoreContextReactContext = exports.SitecoreContext = exports.VisitorIdentification = exports.DefaultEmptyFieldEditingComponentText = exports.DefaultEmptyFieldEditingComponentImage = exports.File = exports.getComponentLibraryStylesheetLinks = exports.BYOCComponent = exports.fetchFEaaSComponentServerProps = void 0;
28
28
  var sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
29
29
  Object.defineProperty(exports, "constants", { enumerable: true, get: function () { return sitecore_jss_1.constants; } });
30
30
  Object.defineProperty(exports, "AxiosDataFetcher", { enumerable: true, get: function () { return sitecore_jss_1.AxiosDataFetcher; } });
@@ -37,10 +37,8 @@ Object.defineProperty(exports, "GraphQLLayoutService", { enumerable: true, get:
37
37
  Object.defineProperty(exports, "RestLayoutService", { enumerable: true, get: function () { return layout_1.RestLayoutService; } });
38
38
  Object.defineProperty(exports, "getChildPlaceholder", { enumerable: true, get: function () { return layout_1.getChildPlaceholder; } });
39
39
  Object.defineProperty(exports, "getFieldValue", { enumerable: true, get: function () { return layout_1.getFieldValue; } });
40
- Object.defineProperty(exports, "RenderingType", { enumerable: true, get: function () { return layout_1.RenderingType; } });
41
- Object.defineProperty(exports, "EDITING_COMPONENT_PLACEHOLDER", { enumerable: true, get: function () { return layout_1.EDITING_COMPONENT_PLACEHOLDER; } });
42
- Object.defineProperty(exports, "EDITING_COMPONENT_ID", { enumerable: true, get: function () { return layout_1.EDITING_COMPONENT_ID; } });
43
40
  Object.defineProperty(exports, "getContentStylesheetLink", { enumerable: true, get: function () { return layout_1.getContentStylesheetLink; } });
41
+ Object.defineProperty(exports, "EditMode", { enumerable: true, get: function () { return layout_1.EditMode; } });
44
42
  var media_1 = require("@sitecore-jss/sitecore-jss/media");
45
43
  Object.defineProperty(exports, "mediaApi", { enumerable: true, get: function () { return media_1.mediaApi; } });
46
44
  var tracking_1 = require("@sitecore-jss/sitecore-jss/tracking");
@@ -52,6 +50,7 @@ var personalize_1 = require("@sitecore-jss/sitecore-jss/personalize");
52
50
  Object.defineProperty(exports, "personalizeLayout", { enumerable: true, get: function () { return personalize_1.personalizeLayout; } });
53
51
  Object.defineProperty(exports, "getPersonalizedRewrite", { enumerable: true, get: function () { return personalize_1.getPersonalizedRewrite; } });
54
52
  Object.defineProperty(exports, "getPersonalizedRewriteData", { enumerable: true, get: function () { return personalize_1.getPersonalizedRewriteData; } });
53
+ Object.defineProperty(exports, "getGroomedVariantIds", { enumerable: true, get: function () { return personalize_1.getGroomedVariantIds; } });
55
54
  Object.defineProperty(exports, "normalizePersonalizedRewrite", { enumerable: true, get: function () { return personalize_1.normalizePersonalizedRewrite; } });
56
55
  Object.defineProperty(exports, "CdpHelper", { enumerable: true, get: function () { return personalize_1.CdpHelper; } });
57
56
  var component_props_service_1 = require("./services/component-props-service");
@@ -81,8 +80,6 @@ var RichText_1 = require("./components/RichText");
81
80
  Object.defineProperty(exports, "RichText", { enumerable: true, get: function () { return RichText_1.RichText; } });
82
81
  var Placeholder_1 = require("./components/Placeholder");
83
82
  Object.defineProperty(exports, "Placeholder", { enumerable: true, get: function () { return Placeholder_1.Placeholder; } });
84
- var EditingComponentPlaceholder_1 = require("./components/EditingComponentPlaceholder");
85
- Object.defineProperty(exports, "EditingComponentPlaceholder", { enumerable: true, get: function () { return EditingComponentPlaceholder_1.EditingComponentPlaceholder; } });
86
83
  var NextImage_1 = require("./components/NextImage");
87
84
  Object.defineProperty(exports, "NextImage", { enumerable: true, get: function () { return NextImage_1.NextImage; } });
88
85
  const FEaaSWrapper = __importStar(require("./components/FEaaSWrapper"));
@@ -103,6 +100,8 @@ Object.defineProperty(exports, "fetchFEaaSComponentServerProps", { enumerable: t
103
100
  Object.defineProperty(exports, "BYOCComponent", { enumerable: true, get: function () { return sitecore_jss_react_1.BYOCComponent; } });
104
101
  Object.defineProperty(exports, "getComponentLibraryStylesheetLinks", { enumerable: true, get: function () { return sitecore_jss_react_1.getComponentLibraryStylesheetLinks; } });
105
102
  Object.defineProperty(exports, "File", { enumerable: true, get: function () { return sitecore_jss_react_1.File; } });
103
+ Object.defineProperty(exports, "DefaultEmptyFieldEditingComponentImage", { enumerable: true, get: function () { return sitecore_jss_react_1.DefaultEmptyFieldEditingComponentImage; } });
104
+ Object.defineProperty(exports, "DefaultEmptyFieldEditingComponentText", { enumerable: true, get: function () { return sitecore_jss_react_1.DefaultEmptyFieldEditingComponentText; } });
106
105
  Object.defineProperty(exports, "VisitorIdentification", { enumerable: true, get: function () { return sitecore_jss_react_1.VisitorIdentification; } });
107
106
  Object.defineProperty(exports, "SitecoreContext", { enumerable: true, get: function () { return sitecore_jss_react_1.SitecoreContext; } });
108
107
  Object.defineProperty(exports, "SitecoreContextReactContext", { enumerable: true, get: function () { return sitecore_jss_react_1.SitecoreContextReactContext; } });
@@ -111,3 +110,6 @@ Object.defineProperty(exports, "useSitecoreContext", { enumerable: true, get: fu
111
110
  Object.defineProperty(exports, "withEditorChromes", { enumerable: true, get: function () { return sitecore_jss_react_1.withEditorChromes; } });
112
111
  Object.defineProperty(exports, "withPlaceholder", { enumerable: true, get: function () { return sitecore_jss_react_1.withPlaceholder; } });
113
112
  Object.defineProperty(exports, "withDatasourceCheck", { enumerable: true, get: function () { return sitecore_jss_react_1.withDatasourceCheck; } });
113
+ Object.defineProperty(exports, "withFieldMetadata", { enumerable: true, get: function () { return sitecore_jss_react_1.withFieldMetadata; } });
114
+ Object.defineProperty(exports, "withEmptyFieldEditingComponent", { enumerable: true, get: function () { return sitecore_jss_react_1.withEmptyFieldEditingComponent; } });
115
+ Object.defineProperty(exports, "EditingScripts", { enumerable: true, get: function () { return sitecore_jss_react_1.EditingScripts; } });
@@ -18,6 +18,18 @@ class MiddlewareBase {
18
18
  var _a, _b;
19
19
  return !!(((_a = req.cookies.get('__prerender_bypass')) === null || _a === void 0 ? void 0 : _a.value) || ((_b = req.cookies.get('__next_preview_data')) === null || _b === void 0 ? void 0 : _b.value));
20
20
  }
21
+ /**
22
+ * Determines if the request is a Next.js (next/link) prefetch request
23
+ * @param {NextRequest} req request
24
+ * @returns {boolean} is prefetch
25
+ */
26
+ isPrefetch(req) {
27
+ return (
28
+ // eslint-disable-next-line prettier/prettier
29
+ req.headers.get('purpose') === 'prefetch' || // Pages Router
30
+ req.headers.get('Next-Router-Prefetch') === '1' // App Router
31
+ );
32
+ }
21
33
  excludeRoute(pathname) {
22
34
  var _a, _b;
23
35
  return (pathname.startsWith('/api/') || // Ignore Next.js API calls
@@ -61,6 +61,15 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
61
61
  sitecore_jss_1.debug.personalize('skipped (no personalization configured)');
62
62
  return response;
63
63
  }
64
+ if (this.isPrefetch(req)) {
65
+ sitecore_jss_1.debug.personalize('skipped (prefetch)');
66
+ // Personalized, but this is a prefetch request.
67
+ // In this case, don't execute a personalize request; otherwise, the metrics for component A/B experiments would be inaccurate.
68
+ // Disable preflight caching to force revalidation on client-side navigation (personalization WILL be influenced).
69
+ // Note the reason we don't move this any earlier in the middleware is that we would then be sacrificing performance for non-personalized pages.
70
+ response.headers.set('x-middleware-cache', 'no-cache');
71
+ return response;
72
+ }
64
73
  yield this.initPersonalizeServer({
65
74
  hostname,
66
75
  siteName: site.name,
@@ -68,32 +77,36 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
68
77
  response,
69
78
  });
70
79
  const params = this.getExperienceParams(req);
71
- sitecore_jss_1.debug.personalize('executing experience for %s %o', personalizeInfo.contentId, params);
72
- let variantId;
73
- // Execute targeted experience in Personalize SDK
74
- // eslint-disable-next-line no-useless-catch
75
- try {
76
- const personalization = yield this.personalize({ personalizeInfo, params, language, timeout }, req);
77
- variantId = personalization.variantId;
78
- }
79
- catch (error) {
80
- throw error;
81
- }
82
- if (!variantId) {
83
- sitecore_jss_1.debug.personalize('skipped (no variant identified)');
84
- return response;
85
- }
86
- if (!personalizeInfo.variantIds.includes(variantId)) {
87
- sitecore_jss_1.debug.personalize('skipped (invalid variant)');
80
+ const executions = this.getPersonalizeExecutions(personalizeInfo, language);
81
+ const identifiedVariantIds = [];
82
+ yield Promise.all(executions.map((execution) => this.personalize({
83
+ friendlyId: execution.friendlyId,
84
+ variantIds: execution.variantIds,
85
+ params,
86
+ language,
87
+ timeout,
88
+ }, req).then((personalization) => {
89
+ const variantId = personalization.variantId;
90
+ if (variantId) {
91
+ if (!execution.variantIds.includes(variantId)) {
92
+ sitecore_jss_1.debug.personalize('invalid variant %s', variantId);
93
+ }
94
+ else {
95
+ identifiedVariantIds.push(variantId);
96
+ }
97
+ }
98
+ })));
99
+ if (identifiedVariantIds.length === 0) {
100
+ sitecore_jss_1.debug.personalize('skipped (no variant(s) identified)');
88
101
  return response;
89
102
  }
90
103
  // Path can be rewritten by previously executed middleware
91
104
  const basePath = (res === null || res === void 0 ? void 0 : res.headers.get('x-sc-rewrite')) || pathname;
92
105
  // Rewrite to persononalized path
93
- const rewritePath = (0, personalize_1.getPersonalizedRewrite)(basePath, { variantId });
106
+ const rewritePath = (0, personalize_1.getPersonalizedRewrite)(basePath, identifiedVariantIds);
94
107
  response = this.rewrite(rewritePath, req, response);
95
- // Disable preflight caching to force revalidation on client-side navigation (personalization may be influenced)
96
- // See https://github.com/vercel/next.js/issues/32727
108
+ // Disable preflight caching to force revalidation on client-side navigation (personalization MAY be influenced).
109
+ // See https://github.com/vercel/next.js/pull/32767
97
110
  response.headers.set('x-middleware-cache', 'no-cache');
98
111
  sitecore_jss_1.debug.personalize('personalize middleware end in %dms: %o', Date.now() - startTimestamp, {
99
112
  rewritePath,
@@ -132,17 +145,18 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
132
145
  });
133
146
  });
134
147
  }
135
- personalize({ params, personalizeInfo, language, timeout, }, request) {
148
+ personalize({ params, friendlyId, language, timeout, variantIds, }, request) {
136
149
  var _a;
137
150
  return __awaiter(this, void 0, void 0, function* () {
138
- const personalizationData = {
151
+ sitecore_jss_1.debug.personalize('executing experience for %s %o', friendlyId, params);
152
+ return (yield (0, server_2.personalize)(request, {
139
153
  channel: this.config.cdpConfig.channel || 'WEB',
140
154
  currency: (_a = this.config.cdpConfig.currency) !== null && _a !== void 0 ? _a : 'USD',
141
- friendlyId: personalizeInfo.contentId,
155
+ friendlyId,
142
156
  params,
143
157
  language,
144
- };
145
- return (yield (0, server_2.personalize)(request, personalizationData, { timeout }));
158
+ pageVariantIds: variantIds,
159
+ }, { timeout }));
146
160
  });
147
161
  }
148
162
  getExperienceParams(req) {
@@ -164,5 +178,51 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
164
178
  // ignore files
165
179
  return pathname.includes('.') || super.excludeRoute(pathname);
166
180
  }
181
+ /**
182
+ * Aggregates personalize executions based on the provided route personalize information and language
183
+ * @param {PersonalizeInfo} personalizeInfo the route personalize information
184
+ * @param {string} language the language
185
+ * @returns An array of personalize executions
186
+ */
187
+ getPersonalizeExecutions(personalizeInfo, language) {
188
+ if (personalizeInfo.variantIds.length === 0) {
189
+ return [];
190
+ }
191
+ const results = [];
192
+ return personalizeInfo.variantIds.reduce((results, variantId) => {
193
+ if (variantId.includes('_')) {
194
+ // Component-level personalization in format "<ComponentID>_<VariantID>"
195
+ const componentId = variantId.split('_')[0];
196
+ const friendlyId = personalize_1.CdpHelper.getComponentFriendlyId(personalizeInfo.pageId, componentId, language, this.config.scope || this.config.edgeConfig.scope);
197
+ const execution = results.find((x) => x.friendlyId === friendlyId);
198
+ if (execution) {
199
+ execution.variantIds.push(variantId);
200
+ }
201
+ else {
202
+ // The default/control variant (format "<ComponentID>_default") is also a valid value returned by the execution
203
+ const defaultVariant = `${componentId}${personalize_1.DEFAULT_VARIANT}`;
204
+ results.push({
205
+ friendlyId,
206
+ variantIds: [defaultVariant, variantId],
207
+ });
208
+ }
209
+ }
210
+ else {
211
+ // Embedded (page-level) personalization in format "<VariantID>"
212
+ const friendlyId = personalize_1.CdpHelper.getPageFriendlyId(personalizeInfo.pageId, language, this.config.scope || this.config.edgeConfig.scope);
213
+ const execution = results.find((x) => x.friendlyId === friendlyId);
214
+ if (execution) {
215
+ execution.variantIds.push(variantId);
216
+ }
217
+ else {
218
+ results.push({
219
+ friendlyId,
220
+ variantIds: [variantId],
221
+ });
222
+ }
223
+ }
224
+ return results;
225
+ }, results);
226
+ }
167
227
  }
168
228
  exports.PersonalizeMiddleware = PersonalizeMiddleware;
@@ -148,13 +148,14 @@ class BaseGraphQLSitemapService {
148
148
  const formatPath = (path) => formatStaticPath(path.replace(/^\/|\/$/g, '').split('/'), language);
149
149
  const aggregatedPaths = [];
150
150
  sitePaths.forEach((item) => {
151
- var _a, _b, _c, _d;
151
+ var _a, _b, _c;
152
152
  if (!item)
153
153
  return;
154
154
  aggregatedPaths.push(formatPath(item.path));
155
- // check for type safety's sake - personalize may be empty depending on query type
156
- if ((_b = (_a = item.route) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.variantIds.length) {
157
- aggregatedPaths.push(...(((_d = (_c = item.route) === null || _c === void 0 ? void 0 : _c.personalization) === null || _d === void 0 ? void 0 : _d.variantIds.map((varId) => formatPath((0, personalize_1.getPersonalizedRewrite)(item.path, { variantId: varId })))) || {}));
155
+ const variantIds = (_c = (_b = (_a = item.route) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.variantIds) === null || _c === void 0 ? void 0 : _c.filter((variantId) => !variantId.includes('_') // exclude component A/B test variants
156
+ );
157
+ if (variantIds === null || variantIds === void 0 ? void 0 : variantIds.length) {
158
+ aggregatedPaths.push(...variantIds.map((varId) => formatPath((0, personalize_1.getPersonalizedRewrite)(item.path, [varId]))));
158
159
  }
159
160
  });
160
161
  return aggregatedPaths;
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveUrl = exports.resetEditorChromes = exports.isEditorActive = exports.tryParseEnvValue = exports.handleEditorFastRefresh = exports.getPublicUrl = void 0;
3
+ exports.resetEditorChromes = exports.isEditorActive = exports.resolveUrl = exports.tryParseEnvValue = exports.handleEditorFastRefresh = exports.getPublicUrl = void 0;
4
4
  var utils_1 = require("./utils");
5
5
  Object.defineProperty(exports, "getPublicUrl", { enumerable: true, get: function () { return utils_1.getPublicUrl; } });
6
6
  Object.defineProperty(exports, "handleEditorFastRefresh", { enumerable: true, get: function () { return utils_1.handleEditorFastRefresh; } });
7
7
  var utils_2 = require("@sitecore-jss/sitecore-jss/utils");
8
8
  Object.defineProperty(exports, "tryParseEnvValue", { enumerable: true, get: function () { return utils_2.tryParseEnvValue; } });
9
- Object.defineProperty(exports, "isEditorActive", { enumerable: true, get: function () { return utils_2.isEditorActive; } });
10
- Object.defineProperty(exports, "resetEditorChromes", { enumerable: true, get: function () { return utils_2.resetEditorChromes; } });
11
9
  Object.defineProperty(exports, "resolveUrl", { enumerable: true, get: function () { return utils_2.resolveUrl; } });
10
+ var editing_1 = require("@sitecore-jss/sitecore-jss/editing");
11
+ Object.defineProperty(exports, "isEditorActive", { enumerable: true, get: function () { return editing_1.isEditorActive; } });
12
+ Object.defineProperty(exports, "resetEditorChromes", { enumerable: true, get: function () { return editing_1.resetEditorChromes; } });
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getJssEditingSecret = exports.handleEditorFastRefresh = exports.getPublicUrl = void 0;
4
- const utils_1 = require("@sitecore-jss/sitecore-jss/utils");
4
+ const editing_1 = require("@sitecore-jss/sitecore-jss/editing");
5
5
  /**
6
6
  * Get the publicUrl.
7
7
  * This is used primarily to enable compatibility with Sitecore editors.
@@ -32,7 +32,7 @@ exports.getPublicUrl = getPublicUrl;
32
32
  * @default forceReload false
33
33
  */
34
34
  const handleEditorFastRefresh = (forceReload = false) => {
35
- if (process.env.NODE_ENV !== 'development' || !(0, utils_1.isEditorActive)()) {
35
+ if (process.env.NODE_ENV !== 'development' || !(0, editing_1.isEditorActive)()) {
36
36
  // Only run if development mode and editor is active
37
37
  return;
38
38
  }
@@ -50,7 +50,7 @@ const handleEditorFastRefresh = (forceReload = false) => {
50
50
  return window.location.reload();
51
51
  setTimeout(() => {
52
52
  console.log('[Sitecore Editor HMR Listener] Sitecore editor does not support Fast Refresh, reloading chromes...');
53
- (0, utils_1.resetEditorChromes)();
53
+ (0, editing_1.resetEditorChromes)();
54
54
  }, 500);
55
55
  };
56
56
  };
@@ -16,14 +16,18 @@ import { Link as ReactLink, LinkPropTypes, } from '@sitecore-jss/sitecore-jss-re
16
16
  export const Link = forwardRef((props, ref) => {
17
17
  const { field, editable = true, children, internalLinkMatcher = /^\//g, showLinkTextWithChildrenPresent } = props, htmlLinkProps = __rest(props, ["field", "editable", "children", "internalLinkMatcher", "showLinkTextWithChildrenPresent"]);
18
18
  if (!field ||
19
- (!field.editable && !field.value && !field.href)) {
19
+ (!field.editable &&
20
+ !field.value &&
21
+ !field.href &&
22
+ !field.metadata)) {
20
23
  return null;
21
24
  }
22
25
  const value = (field.href
23
26
  ? field
24
27
  : field.value);
25
- const { href, querystring, anchor } = value;
26
- const isEditing = editable && field.editable;
28
+ // fallback to {} if value is undefined; could happen if field is LinkFieldValue, href is empty in metadata mode
29
+ const { href, querystring, anchor } = value || {};
30
+ const isEditing = editable && (field.editable || field.metadata);
27
31
  if (href && !isEditing) {
28
32
  const text = showLinkTextWithChildrenPresent || !children ? value.text || value.href : null;
29
33
  // determine if a link is a route or not.
@@ -12,9 +12,12 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { mediaApi } from '@sitecore-jss/sitecore-jss/media';
13
13
  import PropTypes from 'prop-types';
14
14
  import React from 'react';
15
- import { getEEMarkup, } from '@sitecore-jss/sitecore-jss-react';
15
+ import { getEEMarkup, withFieldMetadata, } from '@sitecore-jss/sitecore-jss-react';
16
16
  import Image from 'next/image';
17
- export const NextImage = (_a) => {
17
+ import { withEmptyFieldEditingComponent } from '@sitecore-jss/sitecore-jss-react';
18
+ import { DefaultEmptyFieldEditingComponentImage } from '@sitecore-jss/sitecore-jss-react';
19
+ import { isFieldValueEmpty } from '@sitecore-jss/sitecore-jss/layout';
20
+ export const NextImage = withFieldMetadata(withEmptyFieldEditingComponent((_a) => {
18
21
  var { editable = true, imageParams, field, mediaUrlPrefix, fill, priority } = _a, otherProps = __rest(_a, ["editable", "imageParams", "field", "mediaUrlPrefix", "fill", "priority"]);
19
22
  // next handles src and we use a custom loader,
20
23
  // throw error if these are present
@@ -22,8 +25,7 @@ export const NextImage = (_a) => {
22
25
  throw new Error('Detected src prop. If you wish to use src, use next/image directly.');
23
26
  }
24
27
  const dynamicMedia = field;
25
- if (!field ||
26
- (!dynamicMedia.editable && !dynamicMedia.value && !dynamicMedia.src)) {
28
+ if (!field || (!dynamicMedia.editable && isFieldValueEmpty(dynamicMedia))) {
27
29
  return null;
28
30
  }
29
31
  const imageField = dynamicMedia;
@@ -53,7 +55,7 @@ export const NextImage = (_a) => {
53
55
  return React.createElement(Image, Object.assign({ alt: "" }, imageProps));
54
56
  }
55
57
  return null; // we can't handle the truth
56
- };
58
+ }, { defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentImage }));
57
59
  NextImage.propTypes = {
58
60
  field: PropTypes.oneOfType([
59
61
  PropTypes.shape({
@@ -67,5 +69,9 @@ NextImage.propTypes = {
67
69
  editable: PropTypes.bool,
68
70
  mediaUrlPrefix: PropTypes.instanceOf(RegExp),
69
71
  imageParams: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.number.isRequired, PropTypes.string.isRequired]).isRequired),
72
+ emptyFieldEditingComponent: PropTypes.oneOfType([
73
+ PropTypes.object,
74
+ PropTypes.func,
75
+ ]),
70
76
  };
71
77
  NextImage.displayName = 'NextImage';
@@ -17,7 +17,7 @@ const prefetched = {};
17
17
  export const RichText = (props) => {
18
18
  const { internalLinksSelector = 'a[href^="/"]', prefetchLinks = true, editable = true } = props, rest = __rest(props, ["internalLinksSelector", "prefetchLinks", "editable"]);
19
19
  const hasText = props.field && props.field.value;
20
- const isEditing = editable && props.field && props.field.editable;
20
+ const isEditing = editable && props.field && (props.field.editable || props.field.metadata);
21
21
  const router = useRouter();
22
22
  const richTextRef = useRef(null);
23
23
  useEffect(() => {
@@ -49,7 +49,7 @@ export const RichText = (props) => {
49
49
  link.addEventListener('click', routeHandler, false);
50
50
  });
51
51
  };
52
- return React.createElement(ReactRichText, Object.assign({ ref: richTextRef }, rest));
52
+ return React.createElement(ReactRichText, Object.assign({ ref: richTextRef, editable: editable }, rest));
53
53
  };
54
54
  RichText.propTypes = Object.assign({ internalLinksSelector: PropTypes.string }, RichTextPropTypes);
55
55
  RichText.displayName = 'NextRichText';
@@ -1,3 +1,12 @@
1
1
  export const QUERY_PARAM_EDITING_SECRET = 'secret';
2
- export const QUERY_PARAM_PROTECTION_BYPASS_SITECORE = 'x-sitecore-protection-bypass';
3
- export const QUERY_PARAM_PROTECTION_BYPASS_VERCEL = 'x-vercel-protection-bypass';
2
+ export const QUERY_PARAM_VERCEL_PROTECTION_BYPASS = 'x-vercel-protection-bypass';
3
+ export const QUERY_PARAM_VERCEL_SET_BYPASS_COOKIE = 'x-vercel-set-bypass-cookie';
4
+ /**
5
+ * Headers that should be passed along to (Editing Chromes handler) SSR request.
6
+ * Note these are in lowercase format to match expected `IncomingHttpHeaders`.
7
+ */
8
+ export const EDITING_PASS_THROUGH_HEADERS = ['authorization', 'cookie'];
9
+ /**
10
+ * Default allowed origins for editing requests. This is used to enforce CORS, CSP headers.
11
+ */
12
+ export const EDITING_ALLOWED_ORIGINS = ['https://pages*.cloud', 'https://pages.sitecorecloud.io'];
@@ -7,9 +7,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { QUERY_PARAM_EDITING_SECRET } from './constants';
10
+ import { EDITING_ALLOWED_ORIGINS, QUERY_PARAM_EDITING_SECRET } from './constants';
11
11
  import { getJssEditingSecret } from '../utils/utils';
12
12
  import { debug } from '@sitecore-jss/sitecore-jss';
13
+ import { EditMode } from '@sitecore-jss/sitecore-jss/layout';
14
+ import { enforceCors } from '@sitecore-jss/sitecore-jss/utils';
13
15
  /**
14
16
  * Middleware / handler used in the editing config API route in xmcloud add on (e.g. '/api/editing/config')
15
17
  * provides configuration information to determine feature compatibility on Pages side.
@@ -22,6 +24,10 @@ export class EditingConfigMiddleware {
22
24
  this.config = config;
23
25
  this.handler = (_req, res) => __awaiter(this, void 0, void 0, function* () {
24
26
  const secret = _req.query[QUERY_PARAM_EDITING_SECRET];
27
+ if (!enforceCors(_req, res, EDITING_ALLOWED_ORIGINS)) {
28
+ debug.editing('invalid origin host - set allowed origins in JSS_ALLOWED_ORIGINS environment variable');
29
+ return res.status(401).json({ message: 'Invalid origin' });
30
+ }
25
31
  if (secret !== getJssEditingSecret()) {
26
32
  debug.editing('invalid editing secret - sent "%s" expected "%s"', secret, getJssEditingSecret());
27
33
  return res.status(401).json({ message: 'Missing or invalid editing secret' });
@@ -29,9 +35,11 @@ export class EditingConfigMiddleware {
29
35
  const components = Array.isArray(this.config.components)
30
36
  ? this.config.components
31
37
  : Array.from(this.config.components.keys());
38
+ const editMode = this.config.pagesEditMode || EditMode.Metadata;
32
39
  return res.status(200).json({
33
40
  components,
34
41
  packages: this.config.metadata.packages,
42
+ editMode,
35
43
  });
36
44
  });
37
45
  }
@@ -9,8 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { editingDataDiskCache } from './editing-data-cache';
11
11
  import { isEditingData } from './editing-data';
12
- import { QUERY_PARAM_EDITING_SECRET } from './constants';
12
+ import { EDITING_ALLOWED_ORIGINS, QUERY_PARAM_EDITING_SECRET } from './constants';
13
13
  import { getJssEditingSecret } from '../utils/utils';
14
+ import { enforceCors } from '@sitecore-jss/sitecore-jss/utils';
15
+ import { debug } from '@sitecore-jss/sitecore-jss';
14
16
  /**
15
17
  * Middleware / handler for use in the editing data Next.js API dynamic route (e.g. '/api/editing/data/[key]')
16
18
  * which is required for Sitecore editing support.
@@ -25,6 +27,10 @@ export class EditingDataMiddleware {
25
27
  const { method, query, body } = req;
26
28
  const secret = query[QUERY_PARAM_EDITING_SECRET];
27
29
  const key = query[this.queryParamKey];
30
+ if (!enforceCors(req, res, EDITING_ALLOWED_ORIGINS)) {
31
+ debug.editing('invalid origin host - set allowed origins in JSS_ALLOWED_ORIGINS environment variable');
32
+ return res.status(401).json({ message: 'Invalid origin' });
33
+ }
28
34
  // Validate secret
29
35
  if (secret !== getJssEditingSecret()) {
30
36
  res.status(401).end('Missing or invalid secret');