@sitecore-jss/sitecore-jss-nextjs 21.1.0-canary.99 → 21.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/LICENSE.txt +202 -202
  2. package/README.md +10 -10
  3. package/dist/cjs/components/NextImage.js +8 -2
  4. package/dist/cjs/index.js +7 -2
  5. package/dist/cjs/middleware/index.js +3 -1
  6. package/dist/cjs/middleware/middleware.js +70 -0
  7. package/dist/cjs/middleware/multisite-middleware.js +13 -30
  8. package/dist/cjs/middleware/personalize-middleware.js +14 -40
  9. package/dist/cjs/middleware/redirects-middleware.js +30 -25
  10. package/dist/cjs/services/base-graphql-sitemap-service.js +204 -0
  11. package/dist/cjs/services/graphql-sitemap-service.js +10 -176
  12. package/dist/cjs/services/mutisite-graphql-sitemap-service.js +81 -0
  13. package/dist/esm/components/NextImage.js +8 -2
  14. package/dist/esm/index.js +4 -3
  15. package/dist/esm/middleware/index.js +1 -0
  16. package/dist/esm/middleware/middleware.js +66 -0
  17. package/dist/esm/middleware/multisite-middleware.js +13 -30
  18. package/dist/esm/middleware/personalize-middleware.js +15 -41
  19. package/dist/esm/middleware/redirects-middleware.js +30 -25
  20. package/dist/esm/services/base-graphql-sitemap-service.js +199 -0
  21. package/dist/esm/services/graphql-sitemap-service.js +9 -175
  22. package/dist/esm/services/mutisite-graphql-sitemap-service.js +77 -0
  23. package/package.json +5 -5
  24. package/types/index.d.ts +4 -3
  25. package/types/middleware/index.d.ts +1 -0
  26. package/types/middleware/middleware.d.ts +68 -0
  27. package/types/middleware/multisite-middleware.d.ts +3 -25
  28. package/types/middleware/personalize-middleware.d.ts +8 -41
  29. package/types/middleware/redirects-middleware.d.ts +7 -29
  30. package/types/services/base-graphql-sitemap-service.d.ts +149 -0
  31. package/types/services/graphql-sitemap-service.d.ts +7 -103
  32. package/types/services/mutisite-graphql-sitemap-service.d.ts +42 -0
@@ -9,14 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.GraphQLSitemapService = exports.getSiteEmptyError = exports.sitesError = exports.languageError = void 0;
13
- const graphql_1 = require("@sitecore-jss/sitecore-jss/graphql");
14
- const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
15
- const personalize_1 = require("@sitecore-jss/sitecore-jss/personalize");
16
- const site_1 = require("@sitecore-jss/sitecore-jss/site");
12
+ exports.GraphQLSitemapService = exports.getSiteEmptyError = exports.siteError = exports.languageError = void 0;
13
+ const base_graphql_sitemap_service_1 = require("./base-graphql-sitemap-service");
17
14
  /** @private */
18
15
  exports.languageError = 'The list of languages cannot be empty';
19
- exports.sitesError = 'The list of sites cannot be empty';
16
+ exports.siteError = 'The service needs a site name';
20
17
  /**
21
18
  * @param {string} siteName to inject into error text
22
19
  * @private
@@ -25,103 +22,20 @@ function getSiteEmptyError(siteName) {
25
22
  return `Site "${siteName}" does not exist or site item tree is missing`;
26
23
  }
27
24
  exports.getSiteEmptyError = getSiteEmptyError;
28
- const languageEmptyError = 'The language must be a non-empty string';
29
- /**
30
- * GQL query made dynamic based on schema differences between SXP and XM Cloud
31
- * @param {boolean} usesPersonalize flag to detrmine which variation of a query to run
32
- * @returns GraphQL query to fetch site paths with
33
- */
34
- const defaultQuery = (usesPersonalize) => /* GraphQL */ `
35
- query ${usesPersonalize ? 'PersonalizeSitemapQuery' : 'DefaultSitemapQuery'}(
36
- $siteName: String!
37
- $language: String!
38
- $includedPaths: [String]
39
- $excludedPaths: [String]
40
- $pageSize: Int = 10
41
- $after: String
42
- ) {
43
- site {
44
- siteInfo(site: $siteName) {
45
- routes(
46
- language: $language
47
- includedPaths: $includedPaths
48
- excludedPaths: $excludedPaths
49
- first: $pageSize
50
- after: $after
51
- ){
52
- total
53
- pageInfo {
54
- endCursor
55
- hasNext
56
- }
57
- results {
58
- path: routePath
59
- ${usesPersonalize
60
- ? `
61
- route {
62
- personalization {
63
- variantIds
64
- }
65
- }`
66
- : ''}
67
- }
68
- }
69
- }
70
- }
71
- }
72
- `;
73
25
  /**
74
26
  * Service that fetches the list of site pages using Sitecore's GraphQL API.
27
+ * Used to handle a single site
75
28
  * This list is used for SSG and Export functionality.
76
29
  * @mixes SearchQueryService<PageListQueryResult>
77
30
  */
78
- class GraphQLSitemapService {
79
- /**
80
- * Gets the default query used for fetching the list of site pages
81
- */
82
- get query() {
83
- return defaultQuery(this.options.includePersonalizedRoutes);
84
- }
31
+ class GraphQLSitemapService extends base_graphql_sitemap_service_1.BaseGraphQLSitemapService {
85
32
  /**
86
33
  * Creates an instance of graphQL sitemap service with the provided options
87
34
  * @param {GraphQLSitemapServiceConfig} options instance
88
35
  */
89
36
  constructor(options) {
37
+ super(options);
90
38
  this.options = options;
91
- this.graphQLClient = this.getGraphQLClient();
92
- }
93
- /**
94
- * Fetch sitemap which could be used for generation of static pages during `next export`.
95
- * The `locale` parameter will be used in the item query, but since i18n is not supported,
96
- * the output paths will not include a `language` property.
97
- * @param {string} locale which application supports
98
- * @returns an array of @see StaticPath objects
99
- */
100
- fetchExportSitemap(locale) {
101
- return __awaiter(this, void 0, void 0, function* () {
102
- const formatPath = (path) => ({
103
- params: {
104
- path,
105
- },
106
- });
107
- return this.fetchSitemap([locale], formatPath);
108
- });
109
- }
110
- /**
111
- * Fetch sitemap which could be used for generation of static pages using SSG mode
112
- * @param {string[]} locales locales which application supports
113
- * @returns an array of @see StaticPath objects
114
- */
115
- fetchSSGSitemap(locales) {
116
- return __awaiter(this, void 0, void 0, function* () {
117
- const formatPath = (path, locale) => ({
118
- params: {
119
- path,
120
- },
121
- locale,
122
- });
123
- return this.fetchSitemap(locales, formatPath);
124
- });
125
39
  }
126
40
  /**
127
41
  * Fetch a flat list of all pages that belong to the specificed site and have a
@@ -138,93 +52,13 @@ class GraphQLSitemapService {
138
52
  if (!languages.length) {
139
53
  throw new RangeError(exports.languageError);
140
54
  }
141
- // Get all sites
142
- const sites = this.options.sites;
143
- if (!sites || !sites.length) {
144
- throw new RangeError(exports.sitesError);
145
- }
146
- // Fetch paths for each site
147
- for (let i = 0; i < sites.length; i++) {
148
- const siteName = sites[i];
149
- const multiSiteName = sites.length > 1 ? siteName : undefined;
150
- // Fetch paths using all locales
151
- yield Promise.all(languages.map((language) => __awaiter(this, void 0, void 0, function* () {
152
- if (language === '') {
153
- throw new RangeError(languageEmptyError);
154
- }
155
- sitecore_jss_1.debug.sitemap('fetching sitemap data for %s %s', language, siteName);
156
- const results = yield this.fetchLanguageSitePaths(language, siteName);
157
- const transformedPaths = yield this.transformLanguageSitePaths(results, formatStaticPath, language, multiSiteName);
158
- paths.push(...transformedPaths);
159
- })));
55
+ const siteName = this.options.siteName;
56
+ if (!siteName) {
57
+ throw new RangeError(exports.siteError);
160
58
  }
59
+ paths.push(...(yield this.getTranformedPaths(siteName, languages, formatStaticPath)));
161
60
  return [].concat(...paths);
162
61
  });
163
62
  }
164
- transformLanguageSitePaths(sitePaths, formatStaticPath, language, multiSiteName) {
165
- return __awaiter(this, void 0, void 0, function* () {
166
- const formatPath = (path) => formatStaticPath(path.replace(/^\/|\/$/g, '').split('/'), language);
167
- const aggregatedPaths = [];
168
- sitePaths.forEach((item) => {
169
- var _a, _b, _c, _d, _e, _f;
170
- if (!item)
171
- return;
172
- if (!multiSiteName) {
173
- aggregatedPaths.push(formatPath(item.path));
174
- }
175
- else {
176
- aggregatedPaths.push(formatPath((0, site_1.getSiteRewrite)(item.path, { siteName: multiSiteName })));
177
- }
178
- // check for type safety's sake - personalize may be empty depending on query type
179
- if ((_b = (_a = item.route) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.variantIds.length) {
180
- multiSiteName
181
- ? 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)((0, site_1.getSiteRewrite)(item.path, { siteName: multiSiteName }), {
182
- variantId: varId,
183
- })))) || {}))
184
- : aggregatedPaths.push(...(((_f = (_e = item.route) === null || _e === void 0 ? void 0 : _e.personalization) === null || _f === void 0 ? void 0 : _f.variantIds.map((varId) => formatPath((0, personalize_1.getPersonalizedRewrite)(item.path, { variantId: varId })))) || {}));
185
- }
186
- });
187
- return aggregatedPaths;
188
- });
189
- }
190
- fetchLanguageSitePaths(language, siteName) {
191
- var _a, _b, _c, _d;
192
- return __awaiter(this, void 0, void 0, function* () {
193
- const args = {
194
- siteName: siteName,
195
- language: language,
196
- pageSize: this.options.pageSize,
197
- includedPaths: this.options.includedPaths,
198
- excludedPaths: this.options.excludedPaths,
199
- };
200
- let results = [];
201
- let hasNext = true;
202
- let after = '';
203
- while (hasNext) {
204
- const fetchResponse = yield this.graphQLClient.request(this.query, Object.assign(Object.assign({}, args), { after }));
205
- if (!((_a = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.site) === null || _a === void 0 ? void 0 : _a.siteInfo)) {
206
- throw new RangeError(getSiteEmptyError(siteName));
207
- }
208
- else {
209
- results = results.concat((_b = fetchResponse.site.siteInfo.routes) === null || _b === void 0 ? void 0 : _b.results);
210
- hasNext = (_c = fetchResponse.site.siteInfo.routes) === null || _c === void 0 ? void 0 : _c.pageInfo.hasNext;
211
- after = (_d = fetchResponse.site.siteInfo.routes) === null || _d === void 0 ? void 0 : _d.pageInfo.endCursor;
212
- }
213
- }
214
- return results;
215
- });
216
- }
217
- /**
218
- * Gets a GraphQL client that can make requests to the API. Uses graphql-request as the default
219
- * library for fetching graphql data (@see GraphQLRequestClient). Override this method if you
220
- * want to use something else.
221
- * @returns {GraphQLClient} implementation
222
- */
223
- getGraphQLClient() {
224
- return new graphql_1.GraphQLRequestClient(this.options.endpoint, {
225
- apiKey: this.options.apiKey,
226
- debugger: sitecore_jss_1.debug.sitemap,
227
- });
228
- }
229
63
  }
230
64
  exports.GraphQLSitemapService = GraphQLSitemapService;
@@ -0,0 +1,81 @@
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.MultisiteGraphQLSitemapService = exports.sitesError = void 0;
13
+ const site_1 = require("@sitecore-jss/sitecore-jss/site");
14
+ const base_graphql_sitemap_service_1 = require("./base-graphql-sitemap-service");
15
+ exports.sitesError = 'The list of sites cannot be empty';
16
+ /**
17
+ * Service that fetches the list of site pages using Sitecore's GraphQL API.
18
+ * Used to handle multiple sites
19
+ * This list is used for SSG and Export functionality.
20
+ * @mixes SearchQueryService<PageListQueryResult>
21
+ */
22
+ class MultisiteGraphQLSitemapService extends base_graphql_sitemap_service_1.BaseGraphQLSitemapService {
23
+ /**
24
+ * Creates an instance of graphQL sitemap service with the provided options
25
+ * @param {MultisiteGraphQLSitemapServiceConfig} options instance
26
+ */
27
+ constructor(options) {
28
+ super(options);
29
+ this.options = options;
30
+ }
31
+ /**
32
+ * Fetch a flat list of all pages that belong to all the requested sites and have a
33
+ * version in the specified language(s).
34
+ * @param {string[]} languages Fetch pages that have versions in this language(s).
35
+ * @param {Function} formatStaticPath Function for transforming the raw search results into (@see StaticPath) types.
36
+ * @returns list of pages
37
+ * @throws {RangeError} if the list of languages is empty.
38
+ * @throws {RangeError} if the any of the languages is an empty string.
39
+ */
40
+ fetchSitemap(languages, formatStaticPath) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ const paths = new Array();
43
+ if (!languages.length) {
44
+ throw new RangeError(base_graphql_sitemap_service_1.languageError);
45
+ }
46
+ // Get all sites
47
+ const sites = this.options.sites;
48
+ if (!sites || !sites.length) {
49
+ throw new RangeError(exports.sitesError);
50
+ }
51
+ // Fetch paths for each site
52
+ for (let i = 0; i < sites.length; i++) {
53
+ const siteName = sites[i];
54
+ // Fetch paths using all locales
55
+ paths.push(...(yield this.getTranformedPaths(siteName, languages, formatStaticPath)));
56
+ }
57
+ return [].concat(...paths);
58
+ });
59
+ }
60
+ /**
61
+ * Fetch and return site paths for multisite implementation, with prefixes included
62
+ * @param {string} language path language
63
+ * @param {string} siteName site name
64
+ * @returns modified paths
65
+ */
66
+ fetchLanguageSitePaths(language, siteName) {
67
+ const _super = Object.create(null, {
68
+ fetchLanguageSitePaths: { get: () => super.fetchLanguageSitePaths }
69
+ });
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ const results = yield _super.fetchLanguageSitePaths.call(this, language, siteName);
72
+ results.forEach((item) => {
73
+ if (item) {
74
+ item.path = (0, site_1.getSiteRewrite)(item.path, { siteName: siteName });
75
+ }
76
+ });
77
+ return results;
78
+ });
79
+ }
80
+ }
81
+ exports.MultisiteGraphQLSitemapService = MultisiteGraphQLSitemapService;
@@ -21,7 +21,7 @@ export const sitecoreLoader = ({ src, width }) => {
21
21
  return `${root}?${params}`;
22
22
  };
23
23
  export const NextImage = (_a) => {
24
- var { editable, imageParams, field, mediaUrlPrefix } = _a, otherProps = __rest(_a, ["editable", "imageParams", "field", "mediaUrlPrefix"]);
24
+ var { editable, imageParams, field, mediaUrlPrefix, fill, priority } = _a, otherProps = __rest(_a, ["editable", "imageParams", "field", "mediaUrlPrefix", "fill", "priority"]);
25
25
  // next handles src and we use a custom loader,
26
26
  // throw error if these are present
27
27
  if (otherProps.src) {
@@ -44,11 +44,17 @@ export const NextImage = (_a) => {
44
44
  if (!img) {
45
45
  return null;
46
46
  }
47
- const attrs = Object.assign(Object.assign(Object.assign({}, img), otherProps), { src: mediaApi.updateImageUrl(img.src, imageParams, mediaUrlPrefix) });
47
+ const attrs = Object.assign(Object.assign(Object.assign({}, img), otherProps), { fill,
48
+ priority, src: mediaApi.updateImageUrl(img.src, imageParams, mediaUrlPrefix) });
48
49
  const imageProps = Object.assign(Object.assign({}, attrs), {
49
50
  // force replace /media with /jssmedia in src since we _know_ we will be adding a 'mw' query string parameter
50
51
  // this is required for Sitecore media API resizing to work properly
51
52
  src: mediaApi.replaceMediaUrlPrefix(attrs.src, mediaUrlPrefix) });
53
+ // Exclude `width`, `height` in case image is responsive, `fill` is used
54
+ if (imageProps.fill) {
55
+ delete imageProps.width;
56
+ delete imageProps.height;
57
+ }
52
58
  const loader = (otherProps.loader ? otherProps.loader : sitecoreLoader);
53
59
  if (attrs) {
54
60
  return React.createElement(Image, Object.assign({ alt: "", loader: loader }, imageProps));
package/dist/esm/index.js CHANGED
@@ -1,14 +1,15 @@
1
1
  export { constants, AxiosDataFetcher, NativeDataFetcher, enableDebug, } from '@sitecore-jss/sitecore-jss';
2
- export { isEditorActive, resetEditorChromes, resolveUrl } from '@sitecore-jss/sitecore-jss/utils';
2
+ export { isEditorActive, resetEditorChromes, resolveUrl, tryParseEnvValue, } from '@sitecore-jss/sitecore-jss/utils';
3
3
  export { LayoutServicePageState, GraphQLLayoutService, RestLayoutService, getChildPlaceholder, getFieldValue, RenderingType, EDITING_COMPONENT_PLACEHOLDER, EDITING_COMPONENT_ID, } from '@sitecore-jss/sitecore-jss/layout';
4
4
  export { mediaApi } from '@sitecore-jss/sitecore-jss/media';
5
5
  export { trackingApi, } from '@sitecore-jss/sitecore-jss/tracking';
6
6
  export { GraphQLDictionaryService, RestDictionaryService, } from '@sitecore-jss/sitecore-jss/i18n';
7
- export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, normalizePersonalizedRewrite, CdpHelper, } from '@sitecore-jss/sitecore-jss/personalize';
7
+ export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, normalizePersonalizedRewrite, CdpHelper, PosResolver, } from '@sitecore-jss/sitecore-jss/personalize';
8
8
  export { GraphQLRequestClient } from '@sitecore-jss/sitecore-jss';
9
9
  export { ComponentPropsService } from './services/component-props-service';
10
10
  export { DisconnectedSitemapService } from './services/disconnected-sitemap-service';
11
11
  export { GraphQLSitemapService, } from './services/graphql-sitemap-service';
12
+ export { MultisiteGraphQLSitemapService, } from './services/mutisite-graphql-sitemap-service';
12
13
  export { GraphQLSitemapXmlService, GraphQLErrorPagesService, GraphQLRobotsService, SiteResolver, GraphQLSiteInfoService, getSiteRewrite, getSiteRewriteData, normalizeSiteRewrite, } from '@sitecore-jss/sitecore-jss/site';
13
14
  export { ComponentPropsReactContext, ComponentPropsContext, useComponentProps, } from './components/ComponentPropsContext';
14
15
  export { handleEditorFastRefresh, getPublicUrl } from './utils';
@@ -17,4 +18,4 @@ export { RichText } from './components/RichText';
17
18
  export { Placeholder } from './components/Placeholder';
18
19
  export { EditingComponentPlaceholder } from './components/EditingComponentPlaceholder';
19
20
  export { NextImage } from './components/NextImage';
20
- export { Image, Text, DateField, FEaaSComponent, File, VisitorIdentification, SitecoreContext, SitecoreContextReactContext, withSitecoreContext, useSitecoreContext, withEditorChromes, withPlaceholder, withDatasourceCheck, } from '@sitecore-jss/sitecore-jss-react';
21
+ export { Image, Text, DateField, EditFrame, FEaaSComponent, File, VisitorIdentification, SitecoreContext, SitecoreContextReactContext, withSitecoreContext, useSitecoreContext, withEditorChromes, withPlaceholder, withDatasourceCheck, } from '@sitecore-jss/sitecore-jss-react';
@@ -2,3 +2,4 @@ export { RedirectsMiddleware } from './redirects-middleware';
2
2
  export { PersonalizeMiddleware } from './personalize-middleware';
3
3
  export { MultisiteMiddleware } from './multisite-middleware';
4
4
  export { SiteResolver } from '@sitecore-jss/sitecore-jss/site';
5
+ export { tryParseEnvValue } from '@sitecore-jss/sitecore-jss/utils';
@@ -0,0 +1,66 @@
1
+ export class MiddlewareBase {
2
+ constructor(config) {
3
+ this.config = config;
4
+ this.SITE_SYMBOL = 'sc_site';
5
+ this.defaultHostname = config.defaultHostname || 'localhost';
6
+ }
7
+ /**
8
+ * Determines if mode is preview
9
+ * @param {NextRequest} req request
10
+ * @returns {boolean} is preview
11
+ */
12
+ isPreview(req) {
13
+ var _a, _b;
14
+ 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));
15
+ }
16
+ excludeRoute(pathname) {
17
+ var _a, _b;
18
+ return (pathname.includes('.') || // Ignore files
19
+ pathname.startsWith('/api/') || // Ignore Next.js API calls
20
+ pathname.startsWith('/sitecore/') || // Ignore Sitecore API calls
21
+ pathname.startsWith('/_next') || // Ignore next service calls
22
+ (((_a = this.config) === null || _a === void 0 ? void 0 : _a.excludeRoute) && ((_b = this.config) === null || _b === void 0 ? void 0 : _b.excludeRoute(pathname))));
23
+ }
24
+ /**
25
+ * Safely extract all headers for debug logging
26
+ * Necessary to avoid middleware issue https://github.com/vercel/next.js/issues/39765
27
+ * @param {Headers} incomingHeaders Incoming headers
28
+ * @returns Object with headers as key/value pairs
29
+ */
30
+ extractDebugHeaders(incomingHeaders) {
31
+ const headers = {};
32
+ incomingHeaders.forEach((value, key) => (headers[key] = value));
33
+ return headers;
34
+ }
35
+ /**
36
+ * Provides used language
37
+ * @param {NextRequest} req request
38
+ * @returns {string} language
39
+ */
40
+ getLanguage(req) {
41
+ return req.nextUrl.locale || req.nextUrl.defaultLocale || 'en';
42
+ }
43
+ /**
44
+ * Extract 'host' header
45
+ * @param {NextRequest} req request
46
+ */
47
+ getHostHeader(req) {
48
+ var _a;
49
+ return (_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0];
50
+ }
51
+ /**
52
+ * Get site information.
53
+ * Can not be used in **Preview** mode, since site will not be resolved
54
+ * @param {NextRequest} req request
55
+ * @param {NextResponse} [res] response
56
+ * @returns {SiteInfo} site information
57
+ */
58
+ getSite(req, res) {
59
+ var _a;
60
+ const siteNameCookie = (_a = res === null || res === void 0 ? void 0 : res.cookies.get(this.SITE_SYMBOL)) === null || _a === void 0 ? void 0 : _a.value;
61
+ if (siteNameCookie)
62
+ return this.config.siteResolver.getByName(siteNameCookie);
63
+ const hostname = this.getHostHeader(req) || this.defaultHostname;
64
+ return this.config.siteResolver.getByHost(hostname);
65
+ }
66
+ }
@@ -10,40 +10,39 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { NextResponse } from 'next/server';
11
11
  import { getSiteRewrite } from '@sitecore-jss/sitecore-jss/site';
12
12
  import { debug } from '@sitecore-jss/sitecore-jss';
13
+ import { MiddlewareBase } from './middleware';
13
14
  /**
14
15
  * Middleware / handler for multisite support
15
16
  */
16
- export class MultisiteMiddleware {
17
+ export class MultisiteMiddleware extends MiddlewareBase {
17
18
  /**
18
19
  * @param {MultisiteMiddlewareConfig} [config] Multisite middleware config
19
20
  */
20
21
  constructor(config) {
22
+ super(config);
21
23
  this.config = config;
22
24
  this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
23
- var _a, _b;
25
+ var _a;
24
26
  const pathname = req.nextUrl.pathname;
25
- const hostHeader = (_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0];
26
- const hostname = hostHeader || this.defaultHostname;
27
+ const language = this.getLanguage(req);
28
+ const hostname = this.getHostHeader(req) || this.defaultHostname;
27
29
  debug.multisite('multisite middleware start: %o', {
28
30
  pathname,
31
+ language,
29
32
  hostname,
30
33
  });
31
- if (!hostHeader) {
32
- debug.multisite(`host header is missing, default ${hostname} is used`);
33
- }
34
34
  // Response will be provided if other middleware is run before us
35
35
  let response = res || NextResponse.next();
36
- if (this.excludeRoute(pathname) ||
37
- (this.config.excludeRoute && this.config.excludeRoute(pathname))) {
38
- debug.multisite('skipped (route excluded)');
36
+ if (this.isPreview(req) || this.excludeRoute(pathname)) {
37
+ debug.multisite('skipped (%s)', this.isPreview(req) ? 'preview' : 'route excluded');
39
38
  return response;
40
39
  }
41
40
  // Site name can be forced by query string parameter or cookie
42
- const siteName = req.nextUrl.searchParams.get('sc_site') ||
41
+ const siteName = req.nextUrl.searchParams.get(this.SITE_SYMBOL) ||
43
42
  (this.config.useCookieResolution &&
44
43
  this.config.useCookieResolution(req) &&
45
- ((_b = req.cookies.get('sc_site')) === null || _b === void 0 ? void 0 : _b.value)) ||
46
- this.config.getSite(hostname).name;
44
+ ((_a = req.cookies.get(this.SITE_SYMBOL)) === null || _a === void 0 ? void 0 : _a.value)) ||
45
+ this.config.siteResolver.getByHost(hostname).name;
47
46
  // Rewrite to site specific path
48
47
  const rewritePath = getSiteRewrite(pathname, {
49
48
  siteName,
@@ -53,7 +52,7 @@ export class MultisiteMiddleware {
53
52
  rewriteUrl.pathname = rewritePath;
54
53
  response = NextResponse.rewrite(rewriteUrl);
55
54
  // Share site name with the following executed middlewares
56
- response.cookies.set('sc_site', siteName);
55
+ response.cookies.set(this.SITE_SYMBOL, siteName);
57
56
  // Share rewrite path with following executed middlewares
58
57
  response.headers.set('x-sc-rewrite', rewritePath);
59
58
  debug.multisite('multisite middleware end: %o', {
@@ -64,7 +63,6 @@ export class MultisiteMiddleware {
64
63
  });
65
64
  return response;
66
65
  });
67
- this.defaultHostname = config.defaultHostname || 'localhost';
68
66
  }
69
67
  /**
70
68
  * Gets the Next.js middleware handler with error handling
@@ -82,19 +80,4 @@ export class MultisiteMiddleware {
82
80
  }
83
81
  });
84
82
  }
85
- excludeRoute(pathname) {
86
- if (pathname.includes('.') || // Ignore files
87
- pathname.startsWith('/api/') || // Ignore Next.js API calls
88
- pathname.startsWith('/sitecore/') || // Ignore Sitecore API calls
89
- pathname.startsWith('/_next') // Ignore next service calls
90
- ) {
91
- return true;
92
- }
93
- return false;
94
- }
95
- extractDebugHeaders(incomingHeaders) {
96
- const headers = {};
97
- incomingHeaders.forEach((value, key) => (headers[key] = value));
98
- return headers;
99
- }
100
83
  }
@@ -8,32 +8,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { NextResponse, userAgent } from 'next/server';
11
- import { GraphQLPersonalizeService, CdpService, getPersonalizedRewrite, } from '@sitecore-jss/sitecore-jss/personalize';
11
+ import { GraphQLPersonalizeService, CdpService, getPersonalizedRewrite, PosResolver, } from '@sitecore-jss/sitecore-jss/personalize';
12
12
  import { debug, NativeDataFetcher } from '@sitecore-jss/sitecore-jss';
13
+ import { MiddlewareBase } from './middleware';
13
14
  /**
14
15
  * Middleware / handler to support Sitecore Personalize
15
16
  */
16
- export class PersonalizeMiddleware {
17
+ export class PersonalizeMiddleware extends MiddlewareBase {
17
18
  /**
18
19
  * @param {PersonalizeMiddlewareConfig} [config] Personalize middleware config
19
20
  */
20
21
  constructor(config) {
22
+ super(config);
21
23
  this.config = config;
22
24
  this.handler = (req, res) => __awaiter(this, void 0, void 0, function* () {
23
- var _a, _b;
24
- const hostHeader = (_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0];
25
- const hostname = hostHeader || this.defaultHostname;
26
25
  const pathname = req.nextUrl.pathname;
27
- const language = req.nextUrl.locale || req.nextUrl.defaultLocale || 'en';
28
- const siteName = ((_b = res === null || res === void 0 ? void 0 : res.cookies.get('sc_site')) === null || _b === void 0 ? void 0 : _b.value) || this.config.getSite(hostname).name;
26
+ const language = this.getLanguage(req);
27
+ const hostname = this.getHostHeader(req) || this.defaultHostname;
29
28
  let browserId = this.getBrowserId(req);
30
29
  debug.personalize('personalize middleware start: %o', {
31
30
  pathname,
32
31
  language,
32
+ hostname,
33
+ browserId,
33
34
  });
34
- if (!hostHeader) {
35
- debug.personalize(`host header is missing, default ${hostname} is used`);
36
- }
37
35
  // Response will be provided if other middleware is run before us (e.g. redirects)
38
36
  let response = res || NextResponse.next();
39
37
  if (this.config.disabled && this.config.disabled(req, response)) {
@@ -42,13 +40,13 @@ export class PersonalizeMiddleware {
42
40
  }
43
41
  if (response.redirected || // Don't attempt to personalize a redirect
44
42
  this.isPreview(req) || // No need to personalize for preview (layout data is already prepared for preview)
45
- this.excludeRoute(pathname) ||
46
- (this.config.excludeRoute && this.config.excludeRoute(pathname))) {
43
+ this.excludeRoute(pathname)) {
47
44
  debug.personalize('skipped (%s)', response.redirected ? 'redirected' : this.isPreview(req) ? 'preview' : 'route excluded');
48
45
  return response;
49
46
  }
47
+ const site = this.getSite(req, res);
50
48
  // Get personalization info from Experience Edge
51
- const personalizeInfo = yield this.personalizeService.getPersonalizeInfo(pathname, language, siteName);
49
+ const personalizeInfo = yield this.personalizeService.getPersonalizeInfo(pathname, language, site.name);
52
50
  if (!personalizeInfo) {
53
51
  // Likely an invalid route / language
54
52
  debug.personalize('skipped (personalize info not found)');
@@ -68,7 +66,9 @@ export class PersonalizeMiddleware {
68
66
  // Execute targeted experience in CDP
69
67
  const { ua } = userAgent(req);
70
68
  const params = this.getExperienceParams(req);
71
- const pointOfSale = this.config.getPointOfSale(language);
69
+ const pointOfSale = this.config.getPointOfSale
70
+ ? this.config.getPointOfSale(site, language)
71
+ : PosResolver.resolve(site, language);
72
72
  const variantId = yield this.cdpService.executeExperience(personalizeInfo.contentId, browserId, ua, pointOfSale, params);
73
73
  if (!variantId) {
74
74
  debug.personalize('skipped (no variant identified)');
@@ -94,7 +94,7 @@ export class PersonalizeMiddleware {
94
94
  // Set browserId cookie on the response
95
95
  this.setBrowserId(response, browserId);
96
96
  // Share site name with the following executed middlewares
97
- response.cookies.set('sc_site', siteName);
97
+ response.cookies.set(this.SITE_SYMBOL, site.name);
98
98
  debug.personalize('personalize middleware end: %o', {
99
99
  rewritePath,
100
100
  browserId,
@@ -114,7 +114,6 @@ export class PersonalizeMiddleware {
114
114
  });
115
115
  return (url, data) => fetcher.fetch(url, data);
116
116
  } }));
117
- this.defaultHostname = config.defaultHostname || 'localhost';
118
117
  }
119
118
  /**
120
119
  * Gets the Next.js middleware handler with error handling
@@ -156,29 +155,4 @@ export class PersonalizeMiddleware {
156
155
  },
157
156
  };
158
157
  }
159
- excludeRoute(pathname) {
160
- if (pathname.includes('.') || // Ignore files
161
- pathname.startsWith('/api/') || // Ignore Next.js API calls
162
- pathname.startsWith('/sitecore/') || // Ignore Sitecore API calls
163
- pathname.startsWith('/_next') // Ignore next service calls
164
- ) {
165
- return true;
166
- }
167
- return false;
168
- }
169
- isPreview(req) {
170
- var _a, _b;
171
- 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));
172
- }
173
- /**
174
- * Safely extract all headers for debug logging
175
- * Necessary to avoid middleware issue https://github.com/vercel/next.js/issues/39765
176
- * @param {Headers} incomingHeaders Incoming headers
177
- * @returns Object with headers as key/value pairs
178
- */
179
- extractDebugHeaders(incomingHeaders) {
180
- const headers = {};
181
- incomingHeaders.forEach((value, key) => (headers[key] = value));
182
- return headers;
183
- }
184
158
  }