@sitecore-jss/sitecore-jss-nextjs 22.1.0-canary.57 → 22.1.0-canary.59
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/dist/cjs/editing/editing-render-middleware.js +2 -2
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/middleware/middleware.js +12 -0
- package/dist/cjs/middleware/personalize-middleware.js +85 -25
- package/dist/cjs/services/base-graphql-sitemap-service.js +5 -4
- package/dist/esm/editing/editing-render-middleware.js +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/middleware/middleware.js +12 -0
- package/dist/esm/middleware/personalize-middleware.js +86 -26
- package/dist/esm/services/base-graphql-sitemap-service.js +5 -4
- package/package.json +8 -8
- package/types/editing/editing-render-middleware.d.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/middleware/middleware.d.ts +6 -0
- package/types/middleware/personalize-middleware.d.ts +22 -2
- package/types/services/base-graphql-sitemap-service.d.ts +3 -2
|
@@ -216,8 +216,8 @@ class MetadataHandler {
|
|
|
216
216
|
site: query.sc_site,
|
|
217
217
|
itemId: query.sc_itemid,
|
|
218
218
|
language: query.sc_lang,
|
|
219
|
-
//
|
|
220
|
-
|
|
219
|
+
// for sc_variantId we may employ multiple variants (page-layout + component level)
|
|
220
|
+
variantIds: ((_a = query.sc_variant) === null || _a === void 0 ? void 0 : _a.split(',')) || [personalize_1.DEFAULT_VARIANT],
|
|
221
221
|
version: query.sc_version,
|
|
222
222
|
editMode: layout_1.EditMode.Metadata,
|
|
223
223
|
pageState: query.mode,
|
package/dist/cjs/index.js
CHANGED
|
@@ -23,8 +23,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
27
|
-
exports.EditingScripts = exports.withEmptyFieldEditingComponent = exports.withFieldMetadata = exports.withDatasourceCheck = exports.withPlaceholder = exports.withEditorChromes = exports.useSitecoreContext = exports.withSitecoreContext = exports.SitecoreContextReactContext = exports.SitecoreContext = exports.VisitorIdentification = exports.DefaultEmptyFieldEditingComponentText = exports.DefaultEmptyFieldEditingComponentImage = exports.File = exports.getComponentLibraryStylesheetLinks = exports.BYOCComponent = void 0;
|
|
26
|
+
exports.FEaaSComponent = exports.EditFrame = exports.DateField = exports.Text = exports.Image = exports.Context = exports.ComponentBuilder = exports.BYOCWrapper = exports.FEaaSWrapper = exports.NextImage = exports.Placeholder = exports.RichText = exports.Link = exports.useComponentProps = exports.ComponentPropsContext = exports.ComponentPropsReactContext = exports.normalizeSiteRewrite = exports.getSiteRewriteData = exports.getSiteRewrite = exports.GraphQLSiteInfoService = exports.SiteResolver = exports.GraphQLRobotsService = exports.GraphQLErrorPagesService = exports.GraphQLSitemapXmlService = exports.MultisiteGraphQLSitemapService = exports.GraphQLSitemapService = exports.DisconnectedSitemapService = exports.ComponentPropsService = exports.CdpHelper = exports.normalizePersonalizedRewrite = exports.getGroomedVariantIds = exports.getPersonalizedRewriteData = exports.getPersonalizedRewrite = exports.personalizeLayout = exports.RestDictionaryService = exports.GraphQLDictionaryService = exports.trackingApi = exports.mediaApi = exports.EditMode = exports.getContentStylesheetLink = exports.getFieldValue = exports.getChildPlaceholder = exports.RestLayoutService = exports.GraphQLLayoutService = exports.LayoutServicePageState = exports.debug = exports.enableDebug = exports.NativeDataFetcher = exports.AxiosDataFetcher = exports.constants = void 0;
|
|
27
|
+
exports.EditingScripts = exports.withEmptyFieldEditingComponent = exports.withFieldMetadata = exports.withDatasourceCheck = exports.withPlaceholder = exports.withEditorChromes = exports.useSitecoreContext = exports.withSitecoreContext = exports.SitecoreContextReactContext = exports.SitecoreContext = exports.VisitorIdentification = exports.DefaultEmptyFieldEditingComponentText = exports.DefaultEmptyFieldEditingComponentImage = exports.File = exports.getComponentLibraryStylesheetLinks = exports.BYOCComponent = exports.fetchFEaaSComponentServerProps = void 0;
|
|
28
28
|
var sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
|
|
29
29
|
Object.defineProperty(exports, "constants", { enumerable: true, get: function () { return sitecore_jss_1.constants; } });
|
|
30
30
|
Object.defineProperty(exports, "AxiosDataFetcher", { enumerable: true, get: function () { return sitecore_jss_1.AxiosDataFetcher; } });
|
|
@@ -50,6 +50,7 @@ var personalize_1 = require("@sitecore-jss/sitecore-jss/personalize");
|
|
|
50
50
|
Object.defineProperty(exports, "personalizeLayout", { enumerable: true, get: function () { return personalize_1.personalizeLayout; } });
|
|
51
51
|
Object.defineProperty(exports, "getPersonalizedRewrite", { enumerable: true, get: function () { return personalize_1.getPersonalizedRewrite; } });
|
|
52
52
|
Object.defineProperty(exports, "getPersonalizedRewriteData", { enumerable: true, get: function () { return personalize_1.getPersonalizedRewriteData; } });
|
|
53
|
+
Object.defineProperty(exports, "getGroomedVariantIds", { enumerable: true, get: function () { return personalize_1.getGroomedVariantIds; } });
|
|
53
54
|
Object.defineProperty(exports, "normalizePersonalizedRewrite", { enumerable: true, get: function () { return personalize_1.normalizePersonalizedRewrite; } });
|
|
54
55
|
Object.defineProperty(exports, "CdpHelper", { enumerable: true, get: function () { return personalize_1.CdpHelper; } });
|
|
55
56
|
var component_props_service_1 = require("./services/component-props-service");
|
|
@@ -18,6 +18,18 @@ class MiddlewareBase {
|
|
|
18
18
|
var _a, _b;
|
|
19
19
|
return !!(((_a = req.cookies.get('__prerender_bypass')) === null || _a === void 0 ? void 0 : _a.value) || ((_b = req.cookies.get('__next_preview_data')) === null || _b === void 0 ? void 0 : _b.value));
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Determines if the request is a Next.js (next/link) prefetch request
|
|
23
|
+
* @param {NextRequest} req request
|
|
24
|
+
* @returns {boolean} is prefetch
|
|
25
|
+
*/
|
|
26
|
+
isPrefetch(req) {
|
|
27
|
+
return (
|
|
28
|
+
// eslint-disable-next-line prettier/prettier
|
|
29
|
+
req.headers.get('purpose') === 'prefetch' || // Pages Router
|
|
30
|
+
req.headers.get('Next-Router-Prefetch') === '1' // App Router
|
|
31
|
+
);
|
|
32
|
+
}
|
|
21
33
|
excludeRoute(pathname) {
|
|
22
34
|
var _a, _b;
|
|
23
35
|
return (pathname.startsWith('/api/') || // Ignore Next.js API calls
|
|
@@ -61,6 +61,15 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
|
|
|
61
61
|
sitecore_jss_1.debug.personalize('skipped (no personalization configured)');
|
|
62
62
|
return response;
|
|
63
63
|
}
|
|
64
|
+
if (this.isPrefetch(req)) {
|
|
65
|
+
sitecore_jss_1.debug.personalize('skipped (prefetch)');
|
|
66
|
+
// Personalized, but this is a prefetch request.
|
|
67
|
+
// In this case, don't execute a personalize request; otherwise, the metrics for component A/B experiments would be inaccurate.
|
|
68
|
+
// Disable preflight caching to force revalidation on client-side navigation (personalization WILL be influenced).
|
|
69
|
+
// Note the reason we don't move this any earlier in the middleware is that we would then be sacrificing performance for non-personalized pages.
|
|
70
|
+
response.headers.set('x-middleware-cache', 'no-cache');
|
|
71
|
+
return response;
|
|
72
|
+
}
|
|
64
73
|
yield this.initPersonalizeServer({
|
|
65
74
|
hostname,
|
|
66
75
|
siteName: site.name,
|
|
@@ -68,32 +77,36 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
|
|
|
68
77
|
response,
|
|
69
78
|
});
|
|
70
79
|
const params = this.getExperienceParams(req);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
const executions = this.getPersonalizeExecutions(personalizeInfo, language);
|
|
81
|
+
const identifiedVariantIds = [];
|
|
82
|
+
yield Promise.all(executions.map((execution) => this.personalize({
|
|
83
|
+
friendlyId: execution.friendlyId,
|
|
84
|
+
variantIds: execution.variantIds,
|
|
85
|
+
params,
|
|
86
|
+
language,
|
|
87
|
+
timeout,
|
|
88
|
+
}, req).then((personalization) => {
|
|
89
|
+
const variantId = personalization.variantId;
|
|
90
|
+
if (variantId) {
|
|
91
|
+
if (!execution.variantIds.includes(variantId)) {
|
|
92
|
+
sitecore_jss_1.debug.personalize('invalid variant %s', variantId);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
identifiedVariantIds.push(variantId);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
})));
|
|
99
|
+
if (identifiedVariantIds.length === 0) {
|
|
100
|
+
sitecore_jss_1.debug.personalize('skipped (no variant(s) identified)');
|
|
88
101
|
return response;
|
|
89
102
|
}
|
|
90
103
|
// Path can be rewritten by previously executed middleware
|
|
91
104
|
const basePath = (res === null || res === void 0 ? void 0 : res.headers.get('x-sc-rewrite')) || pathname;
|
|
92
105
|
// Rewrite to persononalized path
|
|
93
|
-
const rewritePath = (0, personalize_1.getPersonalizedRewrite)(basePath,
|
|
106
|
+
const rewritePath = (0, personalize_1.getPersonalizedRewrite)(basePath, identifiedVariantIds);
|
|
94
107
|
response = this.rewrite(rewritePath, req, response);
|
|
95
|
-
// Disable preflight caching to force revalidation on client-side navigation (personalization
|
|
96
|
-
// See https://github.com/vercel/next.js/
|
|
108
|
+
// Disable preflight caching to force revalidation on client-side navigation (personalization MAY be influenced).
|
|
109
|
+
// See https://github.com/vercel/next.js/pull/32767
|
|
97
110
|
response.headers.set('x-middleware-cache', 'no-cache');
|
|
98
111
|
sitecore_jss_1.debug.personalize('personalize middleware end in %dms: %o', Date.now() - startTimestamp, {
|
|
99
112
|
rewritePath,
|
|
@@ -132,17 +145,18 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
|
|
|
132
145
|
});
|
|
133
146
|
});
|
|
134
147
|
}
|
|
135
|
-
personalize({ params,
|
|
148
|
+
personalize({ params, friendlyId, language, timeout, variantIds, }, request) {
|
|
136
149
|
var _a;
|
|
137
150
|
return __awaiter(this, void 0, void 0, function* () {
|
|
138
|
-
|
|
151
|
+
sitecore_jss_1.debug.personalize('executing experience for %s %o', friendlyId, params);
|
|
152
|
+
return (yield (0, server_2.personalize)(request, {
|
|
139
153
|
channel: this.config.cdpConfig.channel || 'WEB',
|
|
140
154
|
currency: (_a = this.config.cdpConfig.currency) !== null && _a !== void 0 ? _a : 'USD',
|
|
141
|
-
friendlyId
|
|
155
|
+
friendlyId,
|
|
142
156
|
params,
|
|
143
157
|
language,
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
pageVariantIds: variantIds,
|
|
159
|
+
}, { timeout }));
|
|
146
160
|
});
|
|
147
161
|
}
|
|
148
162
|
getExperienceParams(req) {
|
|
@@ -164,5 +178,51 @@ class PersonalizeMiddleware extends middleware_1.MiddlewareBase {
|
|
|
164
178
|
// ignore files
|
|
165
179
|
return pathname.includes('.') || super.excludeRoute(pathname);
|
|
166
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Aggregates personalize executions based on the provided route personalize information and language
|
|
183
|
+
* @param {PersonalizeInfo} personalizeInfo the route personalize information
|
|
184
|
+
* @param {string} language the language
|
|
185
|
+
* @returns An array of personalize executions
|
|
186
|
+
*/
|
|
187
|
+
getPersonalizeExecutions(personalizeInfo, language) {
|
|
188
|
+
if (personalizeInfo.variantIds.length === 0) {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
const results = [];
|
|
192
|
+
return personalizeInfo.variantIds.reduce((results, variantId) => {
|
|
193
|
+
if (variantId.includes('_')) {
|
|
194
|
+
// Component-level personalization in format "<ComponentID>_<VariantID>"
|
|
195
|
+
const componentId = variantId.split('_')[0];
|
|
196
|
+
const friendlyId = personalize_1.CdpHelper.getComponentFriendlyId(personalizeInfo.pageId, componentId, language, this.config.scope || this.config.edgeConfig.scope);
|
|
197
|
+
const execution = results.find((x) => x.friendlyId === friendlyId);
|
|
198
|
+
if (execution) {
|
|
199
|
+
execution.variantIds.push(variantId);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// The default/control variant (format "<ComponentID>_default") is also a valid value returned by the execution
|
|
203
|
+
const defaultVariant = `${componentId}${personalize_1.DEFAULT_VARIANT}`;
|
|
204
|
+
results.push({
|
|
205
|
+
friendlyId,
|
|
206
|
+
variantIds: [defaultVariant, variantId],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// Embedded (page-level) personalization in format "<VariantID>"
|
|
212
|
+
const friendlyId = personalize_1.CdpHelper.getPageFriendlyId(personalizeInfo.pageId, language, this.config.scope || this.config.edgeConfig.scope);
|
|
213
|
+
const execution = results.find((x) => x.friendlyId === friendlyId);
|
|
214
|
+
if (execution) {
|
|
215
|
+
execution.variantIds.push(variantId);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
results.push({
|
|
219
|
+
friendlyId,
|
|
220
|
+
variantIds: [variantId],
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return results;
|
|
225
|
+
}, results);
|
|
226
|
+
}
|
|
167
227
|
}
|
|
168
228
|
exports.PersonalizeMiddleware = PersonalizeMiddleware;
|
|
@@ -148,13 +148,14 @@ class BaseGraphQLSitemapService {
|
|
|
148
148
|
const formatPath = (path) => formatStaticPath(path.replace(/^\/|\/$/g, '').split('/'), language);
|
|
149
149
|
const aggregatedPaths = [];
|
|
150
150
|
sitePaths.forEach((item) => {
|
|
151
|
-
var _a, _b, _c
|
|
151
|
+
var _a, _b, _c;
|
|
152
152
|
if (!item)
|
|
153
153
|
return;
|
|
154
154
|
aggregatedPaths.push(formatPath(item.path));
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
const variantIds = (_c = (_b = (_a = item.route) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.variantIds) === null || _c === void 0 ? void 0 : _c.filter((variantId) => !variantId.includes('_') // exclude component A/B test variants
|
|
156
|
+
);
|
|
157
|
+
if (variantIds === null || variantIds === void 0 ? void 0 : variantIds.length) {
|
|
158
|
+
aggregatedPaths.push(...variantIds.map((varId) => formatPath((0, personalize_1.getPersonalizedRewrite)(item.path, [varId]))));
|
|
158
159
|
}
|
|
159
160
|
});
|
|
160
161
|
return aggregatedPaths;
|
|
@@ -211,8 +211,8 @@ export class MetadataHandler {
|
|
|
211
211
|
site: query.sc_site,
|
|
212
212
|
itemId: query.sc_itemid,
|
|
213
213
|
language: query.sc_lang,
|
|
214
|
-
//
|
|
215
|
-
|
|
214
|
+
// for sc_variantId we may employ multiple variants (page-layout + component level)
|
|
215
|
+
variantIds: ((_a = query.sc_variant) === null || _a === void 0 ? void 0 : _a.split(',')) || [DEFAULT_VARIANT],
|
|
216
216
|
version: query.sc_version,
|
|
217
217
|
editMode: EditMode.Metadata,
|
|
218
218
|
pageState: query.mode,
|
package/dist/esm/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { LayoutServicePageState, GraphQLLayoutService, RestLayoutService, getChi
|
|
|
3
3
|
export { mediaApi } from '@sitecore-jss/sitecore-jss/media';
|
|
4
4
|
export { trackingApi, } from '@sitecore-jss/sitecore-jss/tracking';
|
|
5
5
|
export { GraphQLDictionaryService, RestDictionaryService, } from '@sitecore-jss/sitecore-jss/i18n';
|
|
6
|
-
export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, normalizePersonalizedRewrite, CdpHelper, } from '@sitecore-jss/sitecore-jss/personalize';
|
|
6
|
+
export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, getGroomedVariantIds, normalizePersonalizedRewrite, CdpHelper, } from '@sitecore-jss/sitecore-jss/personalize';
|
|
7
7
|
export { ComponentPropsService } from './services/component-props-service';
|
|
8
8
|
export { DisconnectedSitemapService } from './services/disconnected-sitemap-service';
|
|
9
9
|
export { GraphQLSitemapService, } from './services/graphql-sitemap-service';
|
|
@@ -15,6 +15,18 @@ export class MiddlewareBase {
|
|
|
15
15
|
var _a, _b;
|
|
16
16
|
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));
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Determines if the request is a Next.js (next/link) prefetch request
|
|
20
|
+
* @param {NextRequest} req request
|
|
21
|
+
* @returns {boolean} is prefetch
|
|
22
|
+
*/
|
|
23
|
+
isPrefetch(req) {
|
|
24
|
+
return (
|
|
25
|
+
// eslint-disable-next-line prettier/prettier
|
|
26
|
+
req.headers.get('purpose') === 'prefetch' || // Pages Router
|
|
27
|
+
req.headers.get('Next-Router-Prefetch') === '1' // App Router
|
|
28
|
+
);
|
|
29
|
+
}
|
|
18
30
|
excludeRoute(pathname) {
|
|
19
31
|
var _a, _b;
|
|
20
32
|
return (pathname.startsWith('/api/') || // Ignore Next.js API calls
|
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { NextResponse } from 'next/server';
|
|
11
|
-
import { GraphQLPersonalizeService, getPersonalizedRewrite, } from '@sitecore-jss/sitecore-jss/personalize';
|
|
11
|
+
import { GraphQLPersonalizeService, getPersonalizedRewrite, CdpHelper, DEFAULT_VARIANT, } from '@sitecore-jss/sitecore-jss/personalize';
|
|
12
12
|
import { debug } from '@sitecore-jss/sitecore-jss';
|
|
13
13
|
import { MiddlewareBase } from './middleware';
|
|
14
14
|
import { init, personalize } from '@sitecore-cloudsdk/personalize/server';
|
|
@@ -58,6 +58,15 @@ export class PersonalizeMiddleware extends MiddlewareBase {
|
|
|
58
58
|
debug.personalize('skipped (no personalization configured)');
|
|
59
59
|
return response;
|
|
60
60
|
}
|
|
61
|
+
if (this.isPrefetch(req)) {
|
|
62
|
+
debug.personalize('skipped (prefetch)');
|
|
63
|
+
// Personalized, but this is a prefetch request.
|
|
64
|
+
// In this case, don't execute a personalize request; otherwise, the metrics for component A/B experiments would be inaccurate.
|
|
65
|
+
// Disable preflight caching to force revalidation on client-side navigation (personalization WILL be influenced).
|
|
66
|
+
// Note the reason we don't move this any earlier in the middleware is that we would then be sacrificing performance for non-personalized pages.
|
|
67
|
+
response.headers.set('x-middleware-cache', 'no-cache');
|
|
68
|
+
return response;
|
|
69
|
+
}
|
|
61
70
|
yield this.initPersonalizeServer({
|
|
62
71
|
hostname,
|
|
63
72
|
siteName: site.name,
|
|
@@ -65,32 +74,36 @@ export class PersonalizeMiddleware extends MiddlewareBase {
|
|
|
65
74
|
response,
|
|
66
75
|
});
|
|
67
76
|
const params = this.getExperienceParams(req);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
const executions = this.getPersonalizeExecutions(personalizeInfo, language);
|
|
78
|
+
const identifiedVariantIds = [];
|
|
79
|
+
yield Promise.all(executions.map((execution) => this.personalize({
|
|
80
|
+
friendlyId: execution.friendlyId,
|
|
81
|
+
variantIds: execution.variantIds,
|
|
82
|
+
params,
|
|
83
|
+
language,
|
|
84
|
+
timeout,
|
|
85
|
+
}, req).then((personalization) => {
|
|
86
|
+
const variantId = personalization.variantId;
|
|
87
|
+
if (variantId) {
|
|
88
|
+
if (!execution.variantIds.includes(variantId)) {
|
|
89
|
+
debug.personalize('invalid variant %s', variantId);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
identifiedVariantIds.push(variantId);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})));
|
|
96
|
+
if (identifiedVariantIds.length === 0) {
|
|
97
|
+
debug.personalize('skipped (no variant(s) identified)');
|
|
85
98
|
return response;
|
|
86
99
|
}
|
|
87
100
|
// Path can be rewritten by previously executed middleware
|
|
88
101
|
const basePath = (res === null || res === void 0 ? void 0 : res.headers.get('x-sc-rewrite')) || pathname;
|
|
89
102
|
// Rewrite to persononalized path
|
|
90
|
-
const rewritePath = getPersonalizedRewrite(basePath,
|
|
103
|
+
const rewritePath = getPersonalizedRewrite(basePath, identifiedVariantIds);
|
|
91
104
|
response = this.rewrite(rewritePath, req, response);
|
|
92
|
-
// Disable preflight caching to force revalidation on client-side navigation (personalization
|
|
93
|
-
// See https://github.com/vercel/next.js/
|
|
105
|
+
// Disable preflight caching to force revalidation on client-side navigation (personalization MAY be influenced).
|
|
106
|
+
// See https://github.com/vercel/next.js/pull/32767
|
|
94
107
|
response.headers.set('x-middleware-cache', 'no-cache');
|
|
95
108
|
debug.personalize('personalize middleware end in %dms: %o', Date.now() - startTimestamp, {
|
|
96
109
|
rewritePath,
|
|
@@ -129,17 +142,18 @@ export class PersonalizeMiddleware extends MiddlewareBase {
|
|
|
129
142
|
});
|
|
130
143
|
});
|
|
131
144
|
}
|
|
132
|
-
personalize({ params,
|
|
145
|
+
personalize({ params, friendlyId, language, timeout, variantIds, }, request) {
|
|
133
146
|
var _a;
|
|
134
147
|
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
-
|
|
148
|
+
debug.personalize('executing experience for %s %o', friendlyId, params);
|
|
149
|
+
return (yield personalize(request, {
|
|
136
150
|
channel: this.config.cdpConfig.channel || 'WEB',
|
|
137
151
|
currency: (_a = this.config.cdpConfig.currency) !== null && _a !== void 0 ? _a : 'USD',
|
|
138
|
-
friendlyId
|
|
152
|
+
friendlyId,
|
|
139
153
|
params,
|
|
140
154
|
language,
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
pageVariantIds: variantIds,
|
|
156
|
+
}, { timeout }));
|
|
143
157
|
});
|
|
144
158
|
}
|
|
145
159
|
getExperienceParams(req) {
|
|
@@ -161,4 +175,50 @@ export class PersonalizeMiddleware extends MiddlewareBase {
|
|
|
161
175
|
// ignore files
|
|
162
176
|
return pathname.includes('.') || super.excludeRoute(pathname);
|
|
163
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Aggregates personalize executions based on the provided route personalize information and language
|
|
180
|
+
* @param {PersonalizeInfo} personalizeInfo the route personalize information
|
|
181
|
+
* @param {string} language the language
|
|
182
|
+
* @returns An array of personalize executions
|
|
183
|
+
*/
|
|
184
|
+
getPersonalizeExecutions(personalizeInfo, language) {
|
|
185
|
+
if (personalizeInfo.variantIds.length === 0) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
const results = [];
|
|
189
|
+
return personalizeInfo.variantIds.reduce((results, variantId) => {
|
|
190
|
+
if (variantId.includes('_')) {
|
|
191
|
+
// Component-level personalization in format "<ComponentID>_<VariantID>"
|
|
192
|
+
const componentId = variantId.split('_')[0];
|
|
193
|
+
const friendlyId = CdpHelper.getComponentFriendlyId(personalizeInfo.pageId, componentId, language, this.config.scope || this.config.edgeConfig.scope);
|
|
194
|
+
const execution = results.find((x) => x.friendlyId === friendlyId);
|
|
195
|
+
if (execution) {
|
|
196
|
+
execution.variantIds.push(variantId);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// The default/control variant (format "<ComponentID>_default") is also a valid value returned by the execution
|
|
200
|
+
const defaultVariant = `${componentId}${DEFAULT_VARIANT}`;
|
|
201
|
+
results.push({
|
|
202
|
+
friendlyId,
|
|
203
|
+
variantIds: [defaultVariant, variantId],
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// Embedded (page-level) personalization in format "<VariantID>"
|
|
209
|
+
const friendlyId = CdpHelper.getPageFriendlyId(personalizeInfo.pageId, language, this.config.scope || this.config.edgeConfig.scope);
|
|
210
|
+
const execution = results.find((x) => x.friendlyId === friendlyId);
|
|
211
|
+
if (execution) {
|
|
212
|
+
execution.variantIds.push(variantId);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
results.push({
|
|
216
|
+
friendlyId,
|
|
217
|
+
variantIds: [variantId],
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return results;
|
|
222
|
+
}, results);
|
|
223
|
+
}
|
|
164
224
|
}
|
|
@@ -144,13 +144,14 @@ export class BaseGraphQLSitemapService {
|
|
|
144
144
|
const formatPath = (path) => formatStaticPath(path.replace(/^\/|\/$/g, '').split('/'), language);
|
|
145
145
|
const aggregatedPaths = [];
|
|
146
146
|
sitePaths.forEach((item) => {
|
|
147
|
-
var _a, _b, _c
|
|
147
|
+
var _a, _b, _c;
|
|
148
148
|
if (!item)
|
|
149
149
|
return;
|
|
150
150
|
aggregatedPaths.push(formatPath(item.path));
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
const variantIds = (_c = (_b = (_a = item.route) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.variantIds) === null || _c === void 0 ? void 0 : _c.filter((variantId) => !variantId.includes('_') // exclude component A/B test variants
|
|
152
|
+
);
|
|
153
|
+
if (variantIds === null || variantIds === void 0 ? void 0 : variantIds.length) {
|
|
154
|
+
aggregatedPaths.push(...variantIds.map((varId) => formatPath(getPersonalizedRewrite(item.path, [varId]))));
|
|
154
155
|
}
|
|
155
156
|
});
|
|
156
157
|
return aggregatedPaths;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sitecore-jss/sitecore-jss-nextjs",
|
|
3
|
-
"version": "22.1.0-canary.
|
|
3
|
+
"version": "22.1.0-canary.59",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"module": "dist/esm/index.js",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"url": "https://github.com/sitecore/jss/issues"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@sitecore-cloudsdk/personalize": "^0.3.
|
|
32
|
+
"@sitecore-cloudsdk/personalize": "^0.3.1",
|
|
33
33
|
"@types/chai": "^4.3.4",
|
|
34
34
|
"@types/chai-as-promised": "^7.1.5",
|
|
35
35
|
"@types/chai-string": "^1.4.2",
|
|
@@ -65,16 +65,16 @@
|
|
|
65
65
|
"typescript": "~4.9.4"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
|
-
"@sitecore-cloudsdk/events": "^0.3.
|
|
69
|
-
"@sitecore-cloudsdk/personalize": "^0.3.
|
|
68
|
+
"@sitecore-cloudsdk/events": "^0.3.1",
|
|
69
|
+
"@sitecore-cloudsdk/personalize": "^0.3.1",
|
|
70
70
|
"next": "^14.1.0",
|
|
71
71
|
"react": "^18.2.0",
|
|
72
72
|
"react-dom": "^18.2.0"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@sitecore-jss/sitecore-jss": "^22.1.0-canary.
|
|
76
|
-
"@sitecore-jss/sitecore-jss-dev-tools": "^22.1.0-canary.
|
|
77
|
-
"@sitecore-jss/sitecore-jss-react": "^22.1.0-canary.
|
|
75
|
+
"@sitecore-jss/sitecore-jss": "^22.1.0-canary.59",
|
|
76
|
+
"@sitecore-jss/sitecore-jss-dev-tools": "^22.1.0-canary.59",
|
|
77
|
+
"@sitecore-jss/sitecore-jss-react": "^22.1.0-canary.59",
|
|
78
78
|
"@vercel/kv": "^0.2.1",
|
|
79
79
|
"prop-types": "^15.8.1",
|
|
80
80
|
"regex-parser": "^2.2.11",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
},
|
|
83
83
|
"description": "",
|
|
84
84
|
"types": "types/index.d.ts",
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "61064aa0da07225a2929d7894ca05cd3b58a508b",
|
|
86
86
|
"files": [
|
|
87
87
|
"dist",
|
|
88
88
|
"types",
|
package/types/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { LayoutService, LayoutServiceData, LayoutServicePageState, LayoutService
|
|
|
3
3
|
export { mediaApi } from '@sitecore-jss/sitecore-jss/media';
|
|
4
4
|
export { trackingApi, TrackingRequestOptions, CampaignInstance, GoalInstance, OutcomeInstance, EventInstance, PageViewInstance, } from '@sitecore-jss/sitecore-jss/tracking';
|
|
5
5
|
export { DictionaryPhrases, DictionaryService, GraphQLDictionaryService, GraphQLDictionaryServiceConfig, RestDictionaryService, RestDictionaryServiceConfig, } from '@sitecore-jss/sitecore-jss/i18n';
|
|
6
|
-
export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, normalizePersonalizedRewrite, CdpHelper, } from '@sitecore-jss/sitecore-jss/personalize';
|
|
6
|
+
export { personalizeLayout, getPersonalizedRewrite, getPersonalizedRewriteData, getGroomedVariantIds, normalizePersonalizedRewrite, CdpHelper, } from '@sitecore-jss/sitecore-jss/personalize';
|
|
7
7
|
export { ComponentPropsCollection, ComponentPropsError, GetStaticComponentProps, GetServerSideComponentProps, } from './sharedTypes/component-props';
|
|
8
8
|
export { ModuleFactory, Module } from './sharedTypes/module-factory';
|
|
9
9
|
export { ComponentPropsService } from './services/component-props-service';
|
|
@@ -37,6 +37,12 @@ export declare abstract class MiddlewareBase {
|
|
|
37
37
|
* @returns {boolean} is preview
|
|
38
38
|
*/
|
|
39
39
|
protected isPreview(req: NextRequest): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Determines if the request is a Next.js (next/link) prefetch request
|
|
42
|
+
* @param {NextRequest} req request
|
|
43
|
+
* @returns {boolean} is prefetch
|
|
44
|
+
*/
|
|
45
|
+
protected isPrefetch(req: NextRequest): boolean;
|
|
40
46
|
protected excludeRoute(pathname: string): boolean | undefined;
|
|
41
47
|
/**
|
|
42
48
|
* Safely extract all headers for debug logging
|
|
@@ -33,6 +33,10 @@ export type PersonalizeMiddlewareConfig = MiddlewareBaseConfig & {
|
|
|
33
33
|
* Configuration for your Sitecore CDP endpoint
|
|
34
34
|
*/
|
|
35
35
|
cdpConfig: CdpServiceConfig;
|
|
36
|
+
/**
|
|
37
|
+
* Optional Sitecore Personalize scope identifier allowing you to isolate your personalization data between XM Cloud environments
|
|
38
|
+
*/
|
|
39
|
+
scope?: string;
|
|
36
40
|
};
|
|
37
41
|
/**
|
|
38
42
|
* Object model of Experience Context data
|
|
@@ -47,6 +51,13 @@ export type ExperienceParams = {
|
|
|
47
51
|
content: string | undefined;
|
|
48
52
|
};
|
|
49
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* Object model of personalize execution data
|
|
56
|
+
*/
|
|
57
|
+
type PersonalizeExecution = {
|
|
58
|
+
friendlyId: string;
|
|
59
|
+
variantIds: string[];
|
|
60
|
+
};
|
|
50
61
|
/**
|
|
51
62
|
* Middleware / handler to support Sitecore Personalize
|
|
52
63
|
*/
|
|
@@ -68,15 +79,24 @@ export declare class PersonalizeMiddleware extends MiddlewareBase {
|
|
|
68
79
|
request: NextRequest;
|
|
69
80
|
response: NextResponse;
|
|
70
81
|
}): Promise<void>;
|
|
71
|
-
protected personalize({ params,
|
|
72
|
-
personalizeInfo: PersonalizeInfo;
|
|
82
|
+
protected personalize({ params, friendlyId, language, timeout, variantIds, }: {
|
|
73
83
|
params: ExperienceParams;
|
|
84
|
+
friendlyId: string;
|
|
74
85
|
language: string;
|
|
75
86
|
timeout?: number;
|
|
87
|
+
variantIds?: string[];
|
|
76
88
|
}, request: NextRequest): Promise<{
|
|
77
89
|
variantId: string;
|
|
78
90
|
}>;
|
|
79
91
|
protected getExperienceParams(req: NextRequest): ExperienceParams;
|
|
80
92
|
protected excludeRoute(pathname: string): boolean | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Aggregates personalize executions based on the provided route personalize information and language
|
|
95
|
+
* @param {PersonalizeInfo} personalizeInfo the route personalize information
|
|
96
|
+
* @param {string} language the language
|
|
97
|
+
* @returns An array of personalize executions
|
|
98
|
+
*/
|
|
99
|
+
protected getPersonalizeExecutions(personalizeInfo: PersonalizeInfo, language: string): PersonalizeExecution[];
|
|
81
100
|
private handler;
|
|
82
101
|
}
|
|
102
|
+
export {};
|
|
@@ -67,8 +67,9 @@ export type RouteListQueryResult = {
|
|
|
67
67
|
*/
|
|
68
68
|
export interface BaseGraphQLSitemapServiceConfig extends Omit<SiteRouteQueryVariables, 'language' | 'siteName'> {
|
|
69
69
|
/**
|
|
70
|
-
* A flag for whether to include personalized routes in service output
|
|
71
|
-
*
|
|
70
|
+
* A flag for whether to include personalized routes in service output.
|
|
71
|
+
* Only works on XM Cloud for pages using Embedded Personalization (not Component A/B testing).
|
|
72
|
+
* Turned off by default.
|
|
72
73
|
*/
|
|
73
74
|
includePersonalizedRoutes?: boolean;
|
|
74
75
|
/**
|