@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.
- package/LICENSE.txt +202 -202
- package/README.md +10 -10
- package/dist/cjs/components/NextImage.js +8 -2
- package/dist/cjs/index.js +7 -2
- package/dist/cjs/middleware/index.js +3 -1
- package/dist/cjs/middleware/middleware.js +70 -0
- package/dist/cjs/middleware/multisite-middleware.js +13 -30
- package/dist/cjs/middleware/personalize-middleware.js +14 -40
- package/dist/cjs/middleware/redirects-middleware.js +30 -25
- package/dist/cjs/services/base-graphql-sitemap-service.js +204 -0
- package/dist/cjs/services/graphql-sitemap-service.js +10 -176
- package/dist/cjs/services/mutisite-graphql-sitemap-service.js +81 -0
- package/dist/esm/components/NextImage.js +8 -2
- package/dist/esm/index.js +4 -3
- package/dist/esm/middleware/index.js +1 -0
- package/dist/esm/middleware/middleware.js +66 -0
- package/dist/esm/middleware/multisite-middleware.js +13 -30
- package/dist/esm/middleware/personalize-middleware.js +15 -41
- package/dist/esm/middleware/redirects-middleware.js +30 -25
- package/dist/esm/services/base-graphql-sitemap-service.js +199 -0
- package/dist/esm/services/graphql-sitemap-service.js +9 -175
- package/dist/esm/services/mutisite-graphql-sitemap-service.js +77 -0
- package/package.json +5 -5
- package/types/index.d.ts +4 -3
- package/types/middleware/index.d.ts +1 -0
- package/types/middleware/middleware.d.ts +68 -0
- package/types/middleware/multisite-middleware.d.ts +3 -25
- package/types/middleware/personalize-middleware.d.ts +8 -41
- package/types/middleware/redirects-middleware.d.ts +7 -29
- package/types/services/base-graphql-sitemap-service.d.ts +149 -0
- package/types/services/graphql-sitemap-service.d.ts +7 -103
- 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.
|
|
13
|
-
const
|
|
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.
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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), {
|
|
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
|
|
25
|
+
var _a;
|
|
24
26
|
const pathname = req.nextUrl.pathname;
|
|
25
|
-
const
|
|
26
|
-
const hostname =
|
|
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
|
-
(
|
|
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(
|
|
41
|
+
const siteName = req.nextUrl.searchParams.get(this.SITE_SYMBOL) ||
|
|
43
42
|
(this.config.useCookieResolution &&
|
|
44
43
|
this.config.useCookieResolution(req) &&
|
|
45
|
-
((
|
|
46
|
-
this.config.
|
|
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(
|
|
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 =
|
|
28
|
-
const
|
|
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,
|
|
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
|
|
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(
|
|
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
|
}
|