@sitecore-jss/sitecore-jss-nextjs 21.1.0-canary.7 → 21.1.0-canary.70

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 (41) hide show
  1. package/dist/cjs/components/EditingComponentPlaceholder.js +12 -0
  2. package/dist/cjs/components/Link.js +2 -2
  3. package/dist/cjs/editing/editing-data-cache.js +15 -10
  4. package/dist/cjs/editing/editing-data-middleware.js +2 -2
  5. package/dist/cjs/editing/editing-data-service.js +2 -2
  6. package/dist/cjs/editing/editing-render-middleware.js +9 -1
  7. package/dist/cjs/index.js +16 -6
  8. package/dist/cjs/middleware/index.js +5 -1
  9. package/dist/cjs/middleware/multisite-middleware.js +102 -0
  10. package/dist/cjs/middleware/personalize-middleware.js +20 -4
  11. package/dist/cjs/middleware/redirects-middleware.js +75 -42
  12. package/dist/cjs/monitoring/healthcheck-middleware.js +30 -0
  13. package/dist/cjs/monitoring/index.js +5 -0
  14. package/dist/cjs/services/graphql-sitemap-service.js +42 -19
  15. package/dist/esm/components/EditingComponentPlaceholder.js +5 -0
  16. package/dist/esm/components/Link.js +2 -2
  17. package/dist/esm/editing/editing-data-cache.js +15 -10
  18. package/dist/esm/editing/editing-data-middleware.js +2 -2
  19. package/dist/esm/editing/editing-data-service.js +2 -2
  20. package/dist/esm/editing/editing-render-middleware.js +9 -1
  21. package/dist/esm/index.js +3 -3
  22. package/dist/esm/middleware/index.js +2 -0
  23. package/dist/esm/middleware/multisite-middleware.js +98 -0
  24. package/dist/esm/middleware/personalize-middleware.js +20 -4
  25. package/dist/esm/middleware/redirects-middleware.js +75 -42
  26. package/dist/esm/monitoring/healthcheck-middleware.js +26 -0
  27. package/dist/esm/monitoring/index.js +1 -0
  28. package/dist/esm/services/graphql-sitemap-service.js +41 -18
  29. package/monitoring.d.ts +1 -0
  30. package/monitoring.js +1 -0
  31. package/package.json +16 -15
  32. package/types/components/EditingComponentPlaceholder.d.ts +4 -0
  33. package/types/editing/editing-data-cache.d.ts +4 -4
  34. package/types/index.d.ts +3 -3
  35. package/types/middleware/index.d.ts +2 -0
  36. package/types/middleware/multisite-middleware.d.ts +42 -0
  37. package/types/middleware/personalize-middleware.d.ts +11 -0
  38. package/types/middleware/redirects-middleware.d.ts +32 -3
  39. package/types/monitoring/healthcheck-middleware.d.ts +12 -0
  40. package/types/monitoring/index.d.ts +1 -0
  41. package/types/services/graphql-sitemap-service.d.ts +8 -3
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EditingComponentPlaceholder = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
9
+ const Placeholder_1 = require("./Placeholder");
10
+ const EditingComponentPlaceholder = ({ rendering, }) => (react_1.default.createElement("div", { id: layout_1.EDITING_COMPONENT_ID },
11
+ react_1.default.createElement(Placeholder_1.Placeholder, { name: layout_1.EDITING_COMPONENT_PLACEHOLDER, rendering: rendering })));
12
+ exports.EditingComponentPlaceholder = EditingComponentPlaceholder;
@@ -43,13 +43,13 @@ exports.Link = react_1.forwardRef((props, ref) => {
43
43
  const value = (field.href
44
44
  ? field
45
45
  : field.value);
46
- const { href, querystring } = value;
46
+ const { href, querystring, anchor } = value;
47
47
  const isEditing = editable && field.editable;
48
48
  if (href && !isEditing) {
49
49
  const text = showLinkTextWithChildrenPresent || !children ? value.text || value.href : null;
50
50
  // determine if a link is a route or not.
51
51
  if (internalLinkMatcher.test(href)) {
52
- return (react_1.default.createElement(link_1.default, { href: { pathname: href, query: querystring }, key: "link", locale: false },
52
+ return (react_1.default.createElement(link_1.default, { href: { pathname: href, query: querystring, hash: anchor }, key: "link", locale: false },
53
53
  react_1.default.createElement("a", Object.assign({ title: value.title, target: value.target, className: value.class }, htmlLinkProps, { ref: ref }),
54
54
  text,
55
55
  children)));
@@ -22,19 +22,24 @@ class EditingDataDiskCache {
22
22
  }
23
23
  set(key, editingData) {
24
24
  const filePath = this.cache.set(key, JSON.stringify(editingData));
25
- if (!filePath || filePath.length === 0) {
26
- throw new Error(`Editing data cache not set for key ${key} at ${this.cache.root}`);
27
- }
25
+ return new Promise((resolve, reject) => {
26
+ if (!filePath || filePath.length === 0) {
27
+ reject(new Error(`Editing data cache not set for key ${key} at ${this.cache.root}`));
28
+ }
29
+ resolve();
30
+ });
28
31
  }
29
32
  get(key) {
30
33
  const entry = this.cache.get(key);
31
- if (!entry.isCached) {
32
- console.warn(`Editing data cache miss for key ${key} at ${this.cache.root}`);
33
- return undefined;
34
- }
35
- // Remove to preserve disk-space (as a macrotask so as not to block current execution)
36
- setTimeout(() => this.cache.remove(key));
37
- return JSON.parse(entry.value);
34
+ return new Promise((resolve) => {
35
+ if (!entry.isCached) {
36
+ console.warn(`Editing data cache miss for key ${key} at ${this.cache.root}`);
37
+ resolve(undefined);
38
+ }
39
+ // Remove to preserve disk-space (as a macrotask so as not to block current execution)
40
+ setTimeout(() => this.cache.remove(key));
41
+ resolve(JSON.parse(entry.value));
42
+ });
38
43
  }
39
44
  }
40
45
  exports.EditingDataDiskCache = EditingDataDiskCache;
@@ -36,7 +36,7 @@ class EditingDataMiddleware {
36
36
  switch (method) {
37
37
  case 'GET': {
38
38
  // Get cache value
39
- const data = this.editingDataCache.get(key);
39
+ const data = yield this.editingDataCache.get(key);
40
40
  res.status(200).json(data);
41
41
  break;
42
42
  }
@@ -46,7 +46,7 @@ class EditingDataMiddleware {
46
46
  }
47
47
  else {
48
48
  // Set cache value
49
- this.editingDataCache.set(key, body);
49
+ yield this.editingDataCache.set(key, body);
50
50
  res.status(200).end();
51
51
  }
52
52
  break;
@@ -56,7 +56,7 @@ class BasicEditingDataService {
56
56
  key,
57
57
  };
58
58
  sitecore_jss_1.debug.editing('storing editing data for %o: %o', previewData, data);
59
- this.editingDataCache.set(key, data);
59
+ yield this.editingDataCache.set(key, data);
60
60
  return { key };
61
61
  });
62
62
  }
@@ -69,7 +69,7 @@ class BasicEditingDataService {
69
69
  return __awaiter(this, void 0, void 0, function* () {
70
70
  const editingPreviewData = previewData;
71
71
  sitecore_jss_1.debug.editing('retrieving editing data for %o', previewData);
72
- return this.editingDataCache.get(editingPreviewData.key);
72
+ return yield this.editingDataCache.get(editingPreviewData.key);
73
73
  });
74
74
  }
75
75
  }
@@ -12,6 +12,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.extractEditingData = exports.EditingRenderMiddleware = void 0;
13
13
  const constants_1 = require("next/constants");
14
14
  const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
15
+ const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
16
+ const node_html_parser_1 = require("node-html-parser");
15
17
  const editing_data_service_1 = require("./editing-data-service");
16
18
  const utils_1 = require("../utils");
17
19
  /**
@@ -25,7 +27,7 @@ class EditingRenderMiddleware {
25
27
  constructor(config) {
26
28
  var _a, _b, _c, _d;
27
29
  this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
28
- var _e;
30
+ var _e, _f;
29
31
  const { method, query, body, headers } = req;
30
32
  sitecore_jss_1.debug.editing('editing render middleware start: %o', {
31
33
  method,
@@ -94,6 +96,12 @@ class EditingRenderMiddleware {
94
96
  // certain route configurations (e.g. multiple catch-all routes).
95
97
  // The following line will trick it into thinking we're SSR, thus avoiding any router.replace.
96
98
  html = html.replace(constants_1.STATIC_PROPS_ID, constants_1.SERVER_PROPS_ID);
99
+ if (editingData.layoutData.sitecore.context.renderingType === layout_1.RenderingType.Component) {
100
+ // Handle component rendering. Extract component markup only
101
+ html = (_f = node_html_parser_1.parse(html).getElementById(layout_1.EDITING_COMPONENT_ID)) === null || _f === void 0 ? void 0 : _f.innerHTML;
102
+ if (!html)
103
+ throw new Error(`Failed to render component for ${requestUrl}`);
104
+ }
97
105
  const body = { html };
98
106
  // Return expected JSON result
99
107
  sitecore_jss_1.debug.editing('editing render middleware end: %o', { status: 200, body });
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withDatasourceCheck = exports.withPlaceholder = exports.withEditorChromes = exports.useSitecoreContext = exports.withSitecoreContext = exports.SitecoreContextReactContext = exports.SitecoreContext = exports.VisitorIdentification = exports.File = exports.DateField = exports.Text = exports.Image = exports.NextImage = exports.Placeholder = exports.RichText = exports.Link = exports.getPublicUrl = exports.handleEditorFastRefresh = exports.useComponentProps = exports.ComponentPropsContext = exports.ComponentPropsReactContext = exports.GraphQLErrorPagesService = exports.GraphQLSitemapXmlService = exports.GraphQLSitemapService = exports.DisconnectedSitemapService = exports.ComponentPropsService = exports.GraphQLRequestClient = exports.GraphQLRobotsService = exports.CdpHelper = exports.normalizePersonalizedRewrite = exports.getPersonalizedRewriteData = exports.getPersonalizedRewrite = exports.personalizeLayout = exports.RestDictionaryService = exports.GraphQLDictionaryService = exports.trackingApi = exports.mediaApi = exports.getFieldValue = exports.getChildPlaceholder = exports.RestLayoutService = exports.GraphQLLayoutService = exports.LayoutServicePageState = exports.resolveUrl = exports.resetEditorChromes = exports.isEditorActive = exports.enableDebug = exports.NativeDataFetcher = exports.AxiosDataFetcher = exports.constants = void 0;
3
+ exports.File = exports.DateField = exports.Text = exports.Image = exports.NextImage = exports.EditingComponentPlaceholder = exports.Placeholder = exports.RichText = exports.Link = exports.getPublicUrl = exports.handleEditorFastRefresh = exports.useComponentProps = exports.ComponentPropsContext = exports.ComponentPropsReactContext = exports.normalizeSiteRewrite = exports.getSiteRewriteData = exports.getSiteRewrite = exports.GraphQLSiteInfoService = exports.SiteResolver = exports.GraphQLRobotsService = exports.GraphQLErrorPagesService = exports.GraphQLSitemapXmlService = exports.GraphQLSitemapService = exports.DisconnectedSitemapService = exports.ComponentPropsService = exports.GraphQLRequestClient = exports.CdpHelper = exports.normalizePersonalizedRewrite = exports.getPersonalizedRewriteData = exports.getPersonalizedRewrite = exports.personalizeLayout = exports.RestDictionaryService = exports.GraphQLDictionaryService = exports.trackingApi = exports.mediaApi = exports.EDITING_COMPONENT_ID = exports.EDITING_COMPONENT_PLACEHOLDER = exports.RenderingType = exports.getFieldValue = exports.getChildPlaceholder = exports.RestLayoutService = exports.GraphQLLayoutService = exports.LayoutServicePageState = exports.resolveUrl = exports.resetEditorChromes = exports.isEditorActive = exports.enableDebug = exports.NativeDataFetcher = exports.AxiosDataFetcher = exports.constants = void 0;
4
+ exports.withDatasourceCheck = exports.withPlaceholder = exports.withEditorChromes = exports.useSitecoreContext = exports.withSitecoreContext = exports.SitecoreContextReactContext = exports.SitecoreContext = exports.VisitorIdentification = void 0;
4
5
  var sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
5
6
  Object.defineProperty(exports, "constants", { enumerable: true, get: function () { return sitecore_jss_1.constants; } });
6
7
  Object.defineProperty(exports, "AxiosDataFetcher", { enumerable: true, get: function () { return sitecore_jss_1.AxiosDataFetcher; } });
@@ -16,6 +17,9 @@ Object.defineProperty(exports, "GraphQLLayoutService", { enumerable: true, get:
16
17
  Object.defineProperty(exports, "RestLayoutService", { enumerable: true, get: function () { return layout_1.RestLayoutService; } });
17
18
  Object.defineProperty(exports, "getChildPlaceholder", { enumerable: true, get: function () { return layout_1.getChildPlaceholder; } });
18
19
  Object.defineProperty(exports, "getFieldValue", { enumerable: true, get: function () { return layout_1.getFieldValue; } });
20
+ Object.defineProperty(exports, "RenderingType", { enumerable: true, get: function () { return layout_1.RenderingType; } });
21
+ Object.defineProperty(exports, "EDITING_COMPONENT_PLACEHOLDER", { enumerable: true, get: function () { return layout_1.EDITING_COMPONENT_PLACEHOLDER; } });
22
+ Object.defineProperty(exports, "EDITING_COMPONENT_ID", { enumerable: true, get: function () { return layout_1.EDITING_COMPONENT_ID; } });
19
23
  var media_1 = require("@sitecore-jss/sitecore-jss/media");
20
24
  Object.defineProperty(exports, "mediaApi", { enumerable: true, get: function () { return media_1.mediaApi; } });
21
25
  var tracking_1 = require("@sitecore-jss/sitecore-jss/tracking");
@@ -29,8 +33,6 @@ Object.defineProperty(exports, "getPersonalizedRewrite", { enumerable: true, get
29
33
  Object.defineProperty(exports, "getPersonalizedRewriteData", { enumerable: true, get: function () { return personalize_1.getPersonalizedRewriteData; } });
30
34
  Object.defineProperty(exports, "normalizePersonalizedRewrite", { enumerable: true, get: function () { return personalize_1.normalizePersonalizedRewrite; } });
31
35
  Object.defineProperty(exports, "CdpHelper", { enumerable: true, get: function () { return personalize_1.CdpHelper; } });
32
- var site_1 = require("@sitecore-jss/sitecore-jss/site");
33
- Object.defineProperty(exports, "GraphQLRobotsService", { enumerable: true, get: function () { return site_1.GraphQLRobotsService; } });
34
36
  var sitecore_jss_2 = require("@sitecore-jss/sitecore-jss");
35
37
  Object.defineProperty(exports, "GraphQLRequestClient", { enumerable: true, get: function () { return sitecore_jss_2.GraphQLRequestClient; } });
36
38
  var component_props_service_1 = require("./services/component-props-service");
@@ -39,9 +41,15 @@ var disconnected_sitemap_service_1 = require("./services/disconnected-sitemap-se
39
41
  Object.defineProperty(exports, "DisconnectedSitemapService", { enumerable: true, get: function () { return disconnected_sitemap_service_1.DisconnectedSitemapService; } });
40
42
  var graphql_sitemap_service_1 = require("./services/graphql-sitemap-service");
41
43
  Object.defineProperty(exports, "GraphQLSitemapService", { enumerable: true, get: function () { return graphql_sitemap_service_1.GraphQLSitemapService; } });
42
- var site_2 = require("@sitecore-jss/sitecore-jss/site");
43
- Object.defineProperty(exports, "GraphQLSitemapXmlService", { enumerable: true, get: function () { return site_2.GraphQLSitemapXmlService; } });
44
- Object.defineProperty(exports, "GraphQLErrorPagesService", { enumerable: true, get: function () { return site_2.GraphQLErrorPagesService; } });
44
+ var site_1 = require("@sitecore-jss/sitecore-jss/site");
45
+ Object.defineProperty(exports, "GraphQLSitemapXmlService", { enumerable: true, get: function () { return site_1.GraphQLSitemapXmlService; } });
46
+ Object.defineProperty(exports, "GraphQLErrorPagesService", { enumerable: true, get: function () { return site_1.GraphQLErrorPagesService; } });
47
+ Object.defineProperty(exports, "GraphQLRobotsService", { enumerable: true, get: function () { return site_1.GraphQLRobotsService; } });
48
+ Object.defineProperty(exports, "SiteResolver", { enumerable: true, get: function () { return site_1.SiteResolver; } });
49
+ Object.defineProperty(exports, "GraphQLSiteInfoService", { enumerable: true, get: function () { return site_1.GraphQLSiteInfoService; } });
50
+ Object.defineProperty(exports, "getSiteRewrite", { enumerable: true, get: function () { return site_1.getSiteRewrite; } });
51
+ Object.defineProperty(exports, "getSiteRewriteData", { enumerable: true, get: function () { return site_1.getSiteRewriteData; } });
52
+ Object.defineProperty(exports, "normalizeSiteRewrite", { enumerable: true, get: function () { return site_1.normalizeSiteRewrite; } });
45
53
  var ComponentPropsContext_1 = require("./components/ComponentPropsContext");
46
54
  Object.defineProperty(exports, "ComponentPropsReactContext", { enumerable: true, get: function () { return ComponentPropsContext_1.ComponentPropsReactContext; } });
47
55
  Object.defineProperty(exports, "ComponentPropsContext", { enumerable: true, get: function () { return ComponentPropsContext_1.ComponentPropsContext; } });
@@ -55,6 +63,8 @@ var RichText_1 = require("./components/RichText");
55
63
  Object.defineProperty(exports, "RichText", { enumerable: true, get: function () { return RichText_1.RichText; } });
56
64
  var Placeholder_1 = require("./components/Placeholder");
57
65
  Object.defineProperty(exports, "Placeholder", { enumerable: true, get: function () { return Placeholder_1.Placeholder; } });
66
+ var EditingComponentPlaceholder_1 = require("./components/EditingComponentPlaceholder");
67
+ Object.defineProperty(exports, "EditingComponentPlaceholder", { enumerable: true, get: function () { return EditingComponentPlaceholder_1.EditingComponentPlaceholder; } });
58
68
  var NextImage_1 = require("./components/NextImage");
59
69
  Object.defineProperty(exports, "NextImage", { enumerable: true, get: function () { return NextImage_1.NextImage; } });
60
70
  var sitecore_jss_react_1 = require("@sitecore-jss/sitecore-jss-react");
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PersonalizeMiddleware = exports.RedirectsMiddleware = void 0;
3
+ exports.SiteResolver = exports.MultisiteMiddleware = exports.PersonalizeMiddleware = exports.RedirectsMiddleware = void 0;
4
4
  var redirects_middleware_1 = require("./redirects-middleware");
5
5
  Object.defineProperty(exports, "RedirectsMiddleware", { enumerable: true, get: function () { return redirects_middleware_1.RedirectsMiddleware; } });
6
6
  var personalize_middleware_1 = require("./personalize-middleware");
7
7
  Object.defineProperty(exports, "PersonalizeMiddleware", { enumerable: true, get: function () { return personalize_middleware_1.PersonalizeMiddleware; } });
8
+ var multisite_middleware_1 = require("./multisite-middleware");
9
+ Object.defineProperty(exports, "MultisiteMiddleware", { enumerable: true, get: function () { return multisite_middleware_1.MultisiteMiddleware; } });
10
+ var site_1 = require("@sitecore-jss/sitecore-jss/site");
11
+ Object.defineProperty(exports, "SiteResolver", { enumerable: true, get: function () { return site_1.SiteResolver; } });
@@ -0,0 +1,102 @@
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.MultisiteMiddleware = void 0;
13
+ const server_1 = require("next/server");
14
+ const site_1 = require("@sitecore-jss/sitecore-jss/site");
15
+ const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
16
+ /**
17
+ * Middleware / handler for multisite support
18
+ */
19
+ class MultisiteMiddleware {
20
+ /**
21
+ * @param {MultisiteMiddlewareConfig} [config] Multisite middleware config
22
+ */
23
+ constructor(config) {
24
+ this.config = config;
25
+ this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
26
+ var _a;
27
+ const pathname = req.nextUrl.pathname;
28
+ const hostHeader = (_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0];
29
+ const hostname = hostHeader || this.defaultHostname;
30
+ sitecore_jss_1.debug.multisite('multisite middleware start: %o', {
31
+ pathname,
32
+ hostname,
33
+ });
34
+ if (!hostHeader) {
35
+ sitecore_jss_1.debug.multisite(`host header is missing, default ${hostname} is used`);
36
+ }
37
+ // Response will be provided if other middleware is run before us
38
+ let response = res || server_1.NextResponse.next();
39
+ if (this.excludeRoute(pathname) ||
40
+ (this.config.excludeRoute && this.config.excludeRoute(pathname))) {
41
+ sitecore_jss_1.debug.multisite('skipped (route excluded)');
42
+ return response;
43
+ }
44
+ // Site name can be forced by query string parameter or cookie
45
+ const siteName = req.nextUrl.searchParams.get('sc_site') ||
46
+ req.cookies.get('sc_site') ||
47
+ this.config.getSite(hostname).name;
48
+ // Rewrite to site specific path
49
+ const rewritePath = site_1.getSiteRewrite(pathname, {
50
+ siteName,
51
+ });
52
+ // Note an absolute URL is required: https://nextjs.org/docs/messages/middleware-relative-urls
53
+ const rewriteUrl = req.nextUrl.clone();
54
+ rewriteUrl.pathname = rewritePath;
55
+ response = server_1.NextResponse.rewrite(rewriteUrl);
56
+ // Share site name with the following executed middlewares
57
+ response.cookies.set('sc_site', siteName);
58
+ // Share rewrite path with following executed middlewares
59
+ response.headers.set('x-sc-rewrite', rewritePath);
60
+ sitecore_jss_1.debug.multisite('multisite middleware end: %o', {
61
+ rewritePath,
62
+ siteName,
63
+ headers: this.extractDebugHeaders(response.headers),
64
+ cookies: response.cookies,
65
+ });
66
+ return response;
67
+ });
68
+ this.defaultHostname = config.defaultHostname || 'localhost';
69
+ }
70
+ /**
71
+ * Gets the Next.js middleware handler with error handling
72
+ * @returns middleware handler
73
+ */
74
+ getHandler() {
75
+ return (req, res) => __awaiter(this, void 0, void 0, function* () {
76
+ try {
77
+ return yield this.handler(req, res);
78
+ }
79
+ catch (error) {
80
+ console.log('Multisite middleware failed:');
81
+ console.log(error);
82
+ return res || server_1.NextResponse.next();
83
+ }
84
+ });
85
+ }
86
+ excludeRoute(pathname) {
87
+ if (pathname.includes('.') || // Ignore files
88
+ pathname.startsWith('/api/') || // Ignore Next.js API calls
89
+ pathname.startsWith('/sitecore/') || // Ignore Sitecore API calls
90
+ pathname.startsWith('/_next') // Ignore next service calls
91
+ ) {
92
+ return true;
93
+ }
94
+ return false;
95
+ }
96
+ extractDebugHeaders(incomingHeaders) {
97
+ const headers = {};
98
+ incomingHeaders.forEach((value, key) => (headers[key] = value));
99
+ return headers;
100
+ }
101
+ }
102
+ exports.MultisiteMiddleware = MultisiteMiddleware;
@@ -23,13 +23,20 @@ class PersonalizeMiddleware {
23
23
  constructor(config) {
24
24
  this.config = config;
25
25
  this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
26
+ var _a;
27
+ const hostHeader = (_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0];
28
+ const hostname = hostHeader || this.defaultHostname;
26
29
  const pathname = req.nextUrl.pathname;
27
30
  const language = req.nextUrl.locale || req.nextUrl.defaultLocale || 'en';
31
+ const siteName = (res === null || res === void 0 ? void 0 : res.cookies.get('sc_site')) || this.config.getSite(hostname).name;
28
32
  let browserId = this.getBrowserId(req);
29
33
  sitecore_jss_1.debug.personalize('personalize middleware start: %o', {
30
34
  pathname,
31
35
  language,
32
36
  });
37
+ if (!hostHeader) {
38
+ sitecore_jss_1.debug.personalize(`host header is missing, default ${hostname} is used`);
39
+ }
33
40
  // Response will be provided if other middleware is run before us (e.g. redirects)
34
41
  let response = res || server_1.NextResponse.next();
35
42
  if (this.config.disabled && this.config.disabled(req, response)) {
@@ -38,12 +45,13 @@ class PersonalizeMiddleware {
38
45
  }
39
46
  if (response.redirected || // Don't attempt to personalize a redirect
40
47
  this.isPreview(req) || // No need to personalize for preview (layout data is already prepared for preview)
41
- (this.config.excludeRoute || this.excludeRoute)(pathname)) {
48
+ this.excludeRoute(pathname) ||
49
+ (this.config.excludeRoute && this.config.excludeRoute(pathname))) {
42
50
  sitecore_jss_1.debug.personalize('skipped (%s)', response.redirected ? 'redirected' : this.isPreview(req) ? 'preview' : 'route excluded');
43
51
  return response;
44
52
  }
45
53
  // Get personalization info from Experience Edge
46
- const personalizeInfo = yield this.personalizeService.getPersonalizeInfo(pathname, language);
54
+ const personalizeInfo = yield this.personalizeService.getPersonalizeInfo(pathname, language, siteName);
47
55
  if (!personalizeInfo) {
48
56
  // Likely an invalid route / language
49
57
  sitecore_jss_1.debug.personalize('skipped (personalize info not found)');
@@ -73,8 +81,10 @@ class PersonalizeMiddleware {
73
81
  sitecore_jss_1.debug.personalize('skipped (invalid variant)');
74
82
  return response;
75
83
  }
84
+ // Path can be rewritten by previously executed middleware
85
+ const basePath = (res === null || res === void 0 ? void 0 : res.headers.get('x-sc-rewrite')) || pathname;
76
86
  // Rewrite to persononalized path
77
- const rewritePath = personalize_1.getPersonalizedRewrite(pathname, { variantId });
87
+ const rewritePath = personalize_1.getPersonalizedRewrite(basePath, { variantId });
78
88
  // Note an absolute URL is required: https://nextjs.org/docs/messages/middleware-relative-urls
79
89
  const rewriteUrl = req.nextUrl.clone();
80
90
  rewriteUrl.pathname = rewritePath;
@@ -82,8 +92,12 @@ class PersonalizeMiddleware {
82
92
  // Disable preflight caching to force revalidation on client-side navigation (personalization may be influenced)
83
93
  // See https://github.com/vercel/next.js/issues/32727
84
94
  response.headers.set('x-middleware-cache', 'no-cache');
95
+ // Share rewrite path with following executed middlewares
96
+ response.headers.set('x-sc-rewrite', rewritePath);
85
97
  // Set browserId cookie on the response
86
98
  this.setBrowserId(response, browserId);
99
+ // Share site name with the following executed middlewares
100
+ response.cookies.set('sc_site', siteName);
87
101
  sitecore_jss_1.debug.personalize('personalize middleware end: %o', {
88
102
  rewritePath,
89
103
  browserId,
@@ -95,13 +109,15 @@ class PersonalizeMiddleware {
95
109
  // (underlying default 'cross-fetch' is not currently compatible: https://github.com/lquixada/cross-fetch/issues/78)
96
110
  this.personalizeService = new personalize_1.GraphQLPersonalizeService(Object.assign(Object.assign({}, config.edgeConfig), { fetch: fetch }));
97
111
  // NOTE: same here, we provide NativeDataFetcher for compatibility on Next.js Edge Runtime
98
- this.cdpService = new personalize_1.CdpService(Object.assign(Object.assign({}, config.cdpConfig), { dataFetcherResolver: ({ timeout }) => {
112
+ this.cdpService = new personalize_1.CdpService(Object.assign(Object.assign({}, config.cdpConfig), { dataFetcherResolver: ({ timeout, headers, }) => {
99
113
  const fetcher = new sitecore_jss_1.NativeDataFetcher({
100
114
  debugger: sitecore_jss_1.debug.personalize,
101
115
  timeout,
116
+ headers,
102
117
  });
103
118
  return (url, data) => fetcher.fetch(url, data);
104
119
  } }));
120
+ this.defaultHostname = config.defaultHostname || 'localhost';
105
121
  }
106
122
  /**
107
123
  * Gets the Next.js middleware handler with error handling
@@ -25,46 +25,61 @@ class RedirectsMiddleware {
25
25
  * @param {RedirectsMiddlewareConfig} [config] redirects middleware config
26
26
  */
27
27
  constructor(config) {
28
- this.handler = (req) => __awaiter(this, void 0, void 0, function* () {
29
- // Find the redirect from result of RedirectService
30
- const existsRedirect = yield this.getExistsRedirect(req);
31
- if (!existsRedirect) {
32
- return server_1.NextResponse.next();
33
- }
34
- const url = req.nextUrl.clone();
35
- const absoluteUrlRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
36
- if (absoluteUrlRegex.test(existsRedirect.target)) {
37
- url.href = existsRedirect.target;
38
- url.locale = req.nextUrl.locale;
39
- }
40
- else {
41
- url.search = existsRedirect.isQueryStringPreserved ? url.search : '';
42
- const urlFirstPart = existsRedirect.target.split('/')[1];
43
- if (this.locales.includes(urlFirstPart)) {
44
- url.locale = urlFirstPart;
45
- url.pathname = existsRedirect.target.replace(`/${urlFirstPart}`, '');
28
+ this.config = config;
29
+ this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
30
+ const hostname = this.getHostname(req);
31
+ const siteName = (res === null || res === void 0 ? void 0 : res.cookies.get('sc_site')) || this.config.getSite(hostname).name;
32
+ const createResponse = () => __awaiter(this, void 0, void 0, function* () {
33
+ if ((this.config.disabled && this.config.disabled(req, server_1.NextResponse.next())) ||
34
+ this.excludeRoute(req.nextUrl.pathname) ||
35
+ (this.config.excludeRoute && this.config.excludeRoute(req.nextUrl.pathname))) {
36
+ return res || server_1.NextResponse.next();
37
+ }
38
+ // Find the redirect from result of RedirectService
39
+ const existsRedirect = yield this.getExistsRedirect(req, siteName);
40
+ if (!existsRedirect) {
41
+ return res || server_1.NextResponse.next();
42
+ }
43
+ const url = req.nextUrl.clone();
44
+ const absoluteUrlRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
45
+ if (absoluteUrlRegex.test(existsRedirect.target)) {
46
+ url.href = existsRedirect.target;
47
+ url.locale = req.nextUrl.locale;
46
48
  }
47
49
  else {
48
- url.pathname = existsRedirect.target;
50
+ url.search = existsRedirect.isQueryStringPreserved ? url.search : '';
51
+ const urlFirstPart = existsRedirect.target.split('/')[1];
52
+ if (this.locales.includes(urlFirstPart)) {
53
+ url.locale = urlFirstPart;
54
+ url.pathname = existsRedirect.target.replace(`/${urlFirstPart}`, '');
55
+ }
56
+ else {
57
+ url.pathname = existsRedirect.target;
58
+ }
49
59
  }
50
- }
51
- const redirectUrl = decodeURIComponent(url.href);
52
- /** return Response redirect with http code of redirect type **/
53
- switch (existsRedirect.redirectType) {
54
- case site_1.REDIRECT_TYPE_301:
55
- return server_1.NextResponse.redirect(redirectUrl, 301);
56
- case site_1.REDIRECT_TYPE_302:
57
- return server_1.NextResponse.redirect(redirectUrl, 302);
58
- case site_1.REDIRECT_TYPE_SERVER_TRANSFER:
59
- return server_1.NextResponse.rewrite(redirectUrl);
60
- default:
61
- return server_1.NextResponse.next();
62
- }
60
+ const redirectUrl = decodeURIComponent(url.href);
61
+ /** return Response redirect with http code of redirect type **/
62
+ switch (existsRedirect.redirectType) {
63
+ case site_1.REDIRECT_TYPE_301:
64
+ return server_1.NextResponse.redirect(redirectUrl, 301);
65
+ case site_1.REDIRECT_TYPE_302:
66
+ return server_1.NextResponse.redirect(redirectUrl, 302);
67
+ case site_1.REDIRECT_TYPE_SERVER_TRANSFER:
68
+ return server_1.NextResponse.rewrite(redirectUrl);
69
+ default:
70
+ return server_1.NextResponse.next();
71
+ }
72
+ });
73
+ const response = yield createResponse();
74
+ // Share site name with the following executed middlewares
75
+ response.cookies.set('sc_site', siteName);
76
+ return response;
63
77
  });
64
78
  // NOTE: we provide native fetch for compatibility on Next.js Edge Runtime
65
79
  // (underlying default 'cross-fetch' is not currently compatible: https://github.com/lquixada/cross-fetch/issues/78)
66
80
  this.redirectsService = new site_1.GraphQLRedirectsService(Object.assign(Object.assign({}, config), { fetch: fetch }));
67
81
  this.locales = config.locales;
82
+ this.defaultHostname = config.defaultHostname || 'localhost';
68
83
  }
69
84
  /**
70
85
  * Gets the Next.js API route handler
@@ -73,22 +88,40 @@ class RedirectsMiddleware {
73
88
  getHandler() {
74
89
  return this.handler;
75
90
  }
91
+ excludeRoute(pathname) {
92
+ if (pathname.includes('.') || // Ignore files
93
+ pathname.startsWith('/api/') || // Ignore Next.js API calls
94
+ pathname.startsWith('/sitecore/') || // Ignore Sitecore API calls
95
+ pathname.startsWith('/_next') // Ignore next service calls
96
+ ) {
97
+ return true;
98
+ }
99
+ return false;
100
+ }
101
+ getHostname(req) {
102
+ var _a;
103
+ const hostHeader = (_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0];
104
+ return hostHeader || this.defaultHostname;
105
+ }
76
106
  /**
77
107
  * Method returns RedirectInfo when matches
78
- * @param {NextRequest} req
108
+ * @param {NextRequest} req request
109
+ * @param {string} siteName site name
79
110
  * @returns Promise<RedirectInfo | undefined>
80
111
  * @private
81
112
  */
82
- getExistsRedirect(req) {
113
+ getExistsRedirect(req, siteName) {
83
114
  return __awaiter(this, void 0, void 0, function* () {
84
- const redirects = yield this.redirectsService.fetchRedirects();
85
- return redirects.find((redirect) => {
86
- return ((regex_parser_1.default(redirect.pattern.toLowerCase()).test(req.nextUrl.pathname.toLowerCase()) ||
87
- regex_parser_1.default(redirect.pattern.toLowerCase()).test(`/${req.nextUrl.locale}${req.nextUrl.pathname}`.toLowerCase())) &&
88
- (redirect.locale
89
- ? redirect.locale.toLowerCase() === req.nextUrl.locale.toLowerCase()
90
- : true));
91
- });
115
+ const redirects = yield this.redirectsService.fetchRedirects(siteName);
116
+ return redirects.length
117
+ ? redirects.find((redirect) => {
118
+ return ((regex_parser_1.default(redirect.pattern.toLowerCase()).test(req.nextUrl.pathname.toLowerCase()) ||
119
+ regex_parser_1.default(redirect.pattern.toLowerCase()).test(`/${req.nextUrl.locale}${req.nextUrl.pathname}`.toLowerCase())) &&
120
+ (redirect.locale
121
+ ? redirect.locale.toLowerCase() === req.nextUrl.locale.toLowerCase()
122
+ : true));
123
+ })
124
+ : undefined;
92
125
  });
93
126
  }
94
127
  }
@@ -0,0 +1,30 @@
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.HealthcheckMiddleware = void 0;
13
+ /**
14
+ * Middleware / handler for use in healthcheck Next.js API route (e.g. '/api/healthz').
15
+ */
16
+ class HealthcheckMiddleware {
17
+ constructor() {
18
+ this.handler = (_req, res) => __awaiter(this, void 0, void 0, function* () {
19
+ res.status(200).send('Healthy');
20
+ });
21
+ }
22
+ /**
23
+ * Gets the Next.js API route handler
24
+ * @returns route handler
25
+ */
26
+ getHandler() {
27
+ return this.handler;
28
+ }
29
+ }
30
+ exports.HealthcheckMiddleware = HealthcheckMiddleware;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HealthcheckMiddleware = void 0;
4
+ var healthcheck_middleware_1 = require("./healthcheck-middleware");
5
+ Object.defineProperty(exports, "HealthcheckMiddleware", { enumerable: true, get: function () { return healthcheck_middleware_1.HealthcheckMiddleware; } });