From 1f3d27fff6746398733ea3bb76706f00e483d1af Mon Sep 17 00:00:00 2001 From: Addy Pathania Date: Mon, 16 Oct 2023 15:37:57 -0400 Subject: [PATCH 1/5] refactor middleware, upgrade engage to latest --- .../templates/nextjs-personalize/package.json | 2 +- packages/sitecore-jss-nextjs/package.json | 4 +- .../src/middleware/personalize-middleware.ts | 41 ++++++++++++------- yarn.lock | 12 +++--- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json b/packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json index 924f8fdf70..6653194865 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json +++ b/packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "@sitecore/engage": "^1.4.0" + "@sitecore/engage": "^1.4.1" } } diff --git a/packages/sitecore-jss-nextjs/package.json b/packages/sitecore-jss-nextjs/package.json index 3269c94da9..87f1ecb541 100644 --- a/packages/sitecore-jss-nextjs/package.json +++ b/packages/sitecore-jss-nextjs/package.json @@ -30,7 +30,7 @@ "url": "https://github.com/sitecore/jss/issues" }, "devDependencies": { - "@sitecore/engage": "^1.4.0", + "@sitecore/engage": "^1.4.1", "@types/chai": "^4.3.4", "@types/chai-as-promised": "^7.1.5", "@types/chai-string": "^1.4.2", @@ -66,7 +66,7 @@ "typescript": "~4.9.4" }, "peerDependencies": { - "@sitecore/engage": "^1.4.0", + "@sitecore/engage": "^1.4.1", "next": "^13.4.16", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts index ce618a6188..5c60b8b6df 100644 --- a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts +++ b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts @@ -67,6 +67,8 @@ export type ExperienceParams = { /** * Middleware / handler to support Sitecore Personalize + * @param req + * @param res */ export class PersonalizeMiddleware extends MiddlewareBase { private personalizeService: GraphQLPersonalizeService; @@ -101,13 +103,18 @@ export class PersonalizeMiddleware extends MiddlewareBase { }; } - protected initializeEngageServer(site: SiteInfo, language: string): EngageServer { + protected initializeEngageServer( + hostName: string, + site: SiteInfo, + language: string + ): EngageServer { const engageServer = initServer({ clientKey: this.config.cdpConfig.clientKey, targetURL: this.config.cdpConfig.endpoint, pointOfSale: this.config.getPointOfSale ? this.config.getPointOfSale(site, language) : PosResolver.resolve(site, language), + cookieDomain: hostName, forceServerCookieMode: true, }); @@ -171,16 +178,6 @@ export class PersonalizeMiddleware extends MiddlewareBase { } const site = this.getSite(req, response); - const engageServer = this.initializeEngageServer(site, language); - - // creates the browser ID cookie on the server side - // and includes the cookie in the response header - try { - await engageServer.handleCookie(req, response, timeout); - } catch (error) { - debug.personalize('skipped (browser id generation failed)'); - throw error; - } // Get personalization info from Experience Edge const personalizeInfo = await this.personalizeService.getPersonalizeInfo( @@ -199,6 +196,16 @@ export class PersonalizeMiddleware extends MiddlewareBase { return response; } + const engageServer = this.initializeEngageServer(hostname, site, language); + + // creates the browser ID cookie on the server side + // and includes the cookie in the response header + try { + await engageServer.handleCookie(req, response, timeout); + } catch (error) { + debug.personalize('skipped (browser id generation failed)'); + throw error; + } const params = this.getExperienceParams(req); debug.personalize('executing experience for %s %s %o', personalizeInfo.contentId, params); @@ -240,18 +247,24 @@ export class PersonalizeMiddleware extends MiddlewareBase { const rewritePath = getPersonalizedRewrite(basePath, { variantId }); // Note an absolute URL is required: https://nextjs.org/docs/messages/middleware-relative-urls const rewriteUrl = req.nextUrl.clone(); + rewriteUrl.pathname = rewritePath; - response = NextResponse.rewrite(rewriteUrl); + response = NextResponse.rewrite(rewriteUrl, response); + + const setCookieHeader = response.headers.get('set-cookie'); // Disable preflight caching to force revalidation on client-side navigation (personalization may be influenced) // See https://github.com/vercel/next.js/issues/32727 response.headers.set('x-middleware-cache', 'no-cache'); - // Share rewrite path with following executed middlewares + // Share rewrite path with following executed middlewaressni response.headers.set('x-sc-rewrite', rewritePath); - // Share site name with the following executed middlewares response.cookies.set(this.SITE_SYMBOL, site.name); + if (setCookieHeader) { + response.headers.set('set-cookie', setCookieHeader); + } + debug.personalize('personalize middleware end in %dms: %o', Date.now() - startTimestamp, { rewritePath, headers: this.extractDebugHeaders(response.headers), diff --git a/yarn.lock b/yarn.lock index a2c2799c89..d0dd5465fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6606,7 +6606,7 @@ __metadata: "@sitecore-jss/sitecore-jss": 21.6.0-canary.4 "@sitecore-jss/sitecore-jss-dev-tools": 21.6.0-canary.4 "@sitecore-jss/sitecore-jss-react": 21.6.0-canary.4 - "@sitecore/engage": ^1.4.0 + "@sitecore/engage": ^1.4.1 "@types/chai": ^4.3.4 "@types/chai-as-promised": ^7.1.5 "@types/chai-string": ^1.4.2 @@ -6646,7 +6646,7 @@ __metadata: ts-node: ^10.9.1 typescript: ~4.9.4 peerDependencies: - "@sitecore/engage": ^1.4.0 + "@sitecore/engage": ^1.4.1 next: ^13.4.16 react: ^18.2.0 react-dom: ^18.2.0 @@ -6887,10 +6887,10 @@ __metadata: languageName: unknown linkType: soft -"@sitecore/engage@npm:^1.4.0": - version: 1.4.0 - resolution: "@sitecore/engage@npm:1.4.0" - checksum: f656045dfcb65f63ff44af195c9ae92d375a237bdf91a4638e9d296df2d143837145f13ca033aeabd03323c900ee5c78249d2967c7665368fde82ef2e758ad43 +"@sitecore/engage@npm:^1.4.1": + version: 1.4.1 + resolution: "@sitecore/engage@npm:1.4.1" + checksum: 582b7a55ba407765def12518114790fb1735c359e60fe4594102a5e643539b148a494b02bf71970bcafc807b92fe19a1ab8ff7c2af3db2c080ab36ec2eb16d57 languageName: node linkType: hard From 62fcc3c9a354df5e9d5518ca93a5df5840f8cb18 Mon Sep 17 00:00:00 2001 From: Addy Pathania Date: Mon, 16 Oct 2023 15:47:34 -0400 Subject: [PATCH 2/5] update changelog --- CHANGELOG.md | 15 ++++++++++----- .../src/middleware/personalize-middleware.ts | 4 +--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd823e517d..dd9329a123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,16 @@ Our versioning strategy is as follows: * `[templates/nextjs-sxa]` Fix shown horizontal scrollbar in EE mode. ([#1625](https://github.com/Sitecore/jss/pull/1625)), ([#1626](https://github.com/Sitecore/jss/pull/1626)) * `[sitecore-jss-nextjs]` Fix issue when redirects works each every other times. ([#1629](https://github.com/Sitecore/jss/pull/1629)) +## 21.5.0 + +### 🐛 Bug Fixes + +* `[templates/nextjs-personalize]` Fix cookie domain for localhost ([#1609](https://github.com/Sitecore/jss/pull/1609)) + +### 🛠 Breaking Changes + +* `[templates/nextjs]` `[sitecore-jss-nextjs]` Upgrade of @sitecore/engage to 1.4.0, now this dependency has been added as a peer dependency to @sitecore-jss-nextjs package in order to replace the existing CDP service in the @sitecore-jss/sitecore-jss with the new functions/features introduced in the engage SDK. ([#1609](https://github.com/Sitecore/jss/pull/1609)) ([#1633](https://github.com/Sitecore/jss/pull/1633)) + ## 21.4.0 ### 🎉 New Features & Improvements @@ -64,14 +74,9 @@ Our versioning strategy is as follows: * `[templates/nextjs-sxa]` Don't let Image component wrap with tag when TargetUrl is not configured. ([#1593](https://github.com/Sitecore/jss/issues/1593)) * `[templates/nextjs]` Next config header plugin for CORS. ([#1597](https://github.com/Sitecore/jss/pull/1597)) * `[templates/nextjs]` Ensure dictionary data is only fetched when layout data is present for a route ([#1608](https://github.com/Sitecore/jss/pull/1608)) -* `[templates/nextjs-personalize]` Fix cookie domain for localhost ([#1609](https://github.com/Sitecore/jss/pull/1609)) * `[sitecore-jss-react-forms]` Form should be blocked while submit is in progress to avoid submit spam ([#1611](https://github.com/Sitecore/jss/pull/1611)) * `[templates/nextjs]` Fix linting errors, fix type error by upgrading @react/types to v18.2.22 ([#1613](https://github.com/Sitecore/jss/pull/1613)) -### 🛠 Breaking Changes - -* `[templates/nextjs]` `[sitecore-jss-nextjs]` Upgrade @sitecore/engage to 1.4.0 also, this dependency has been added to @sitecore-jss-nextjs package to make use of the latest features from the SDK. ([#1609](https://github.com/Sitecore/jss/pull/1609)) - ## 21.3.1 ### 🐛 Bug Fixes diff --git a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts index 5c60b8b6df..62e542ef4f 100644 --- a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts +++ b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts @@ -67,8 +67,6 @@ export type ExperienceParams = { /** * Middleware / handler to support Sitecore Personalize - * @param req - * @param res */ export class PersonalizeMiddleware extends MiddlewareBase { private personalizeService: GraphQLPersonalizeService; @@ -256,7 +254,7 @@ export class PersonalizeMiddleware extends MiddlewareBase { // Disable preflight caching to force revalidation on client-side navigation (personalization may be influenced) // See https://github.com/vercel/next.js/issues/32727 response.headers.set('x-middleware-cache', 'no-cache'); - // Share rewrite path with following executed middlewaressni + // Share rewrite path with following executed middleware response.headers.set('x-sc-rewrite', rewritePath); // Share site name with the following executed middlewares response.cookies.set(this.SITE_SYMBOL, site.name); From 46a9772ffbab5b3849d5da4d8d1dc6a1351b8157 Mon Sep 17 00:00:00 2001 From: Addy Pathania Date: Mon, 16 Oct 2023 16:59:46 -0400 Subject: [PATCH 3/5] preserve cookie response --- .../src/middleware/personalize-middleware.ts | 19 ++++++++++++++----- yarn.lock | 1 - 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts index 62e542ef4f..6ee6bf2978 100644 --- a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts +++ b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts @@ -245,12 +245,13 @@ export class PersonalizeMiddleware extends MiddlewareBase { const rewritePath = getPersonalizedRewrite(basePath, { variantId }); // Note an absolute URL is required: https://nextjs.org/docs/messages/middleware-relative-urls const rewriteUrl = req.nextUrl.clone(); + + // Preserve cookies from previous response + const cookies = response.cookies.getAll(); rewriteUrl.pathname = rewritePath; response = NextResponse.rewrite(rewriteUrl, response); - const setCookieHeader = response.headers.get('set-cookie'); - // Disable preflight caching to force revalidation on client-side navigation (personalization may be influenced) // See https://github.com/vercel/next.js/issues/32727 response.headers.set('x-middleware-cache', 'no-cache'); @@ -259,9 +260,17 @@ export class PersonalizeMiddleware extends MiddlewareBase { // Share site name with the following executed middlewares response.cookies.set(this.SITE_SYMBOL, site.name); - if (setCookieHeader) { - response.headers.set('set-cookie', setCookieHeader); - } + // Restore cookies from previous response since + // browserId cookie gets omitted after rewrite + cookies.forEach((cookie) => { + response.cookies.set(cookie.name, cookie.value, { + domain: cookie.domain, + expires: cookie.expires, + maxAge: cookie.maxAge, + sameSite: cookie.sameSite, + secure: cookie.secure, + }); + }); debug.personalize('personalize middleware end in %dms: %o', Date.now() - startTimestamp, { rewritePath, diff --git a/yarn.lock b/yarn.lock index a450e65613..1038417e46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6904,7 +6904,6 @@ __metadata: languageName: unknown linkType: soft - "@sitecore/byoc@npm:>=0.0.17": version: 0.0.17 resolution: "@sitecore/byoc@npm:0.0.17" From cb37fc9a3d6fbe8a4d34e7af0080dbbe02cf0e12 Mon Sep 17 00:00:00 2001 From: Addy Pathania <89087450+sc-addypathania@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:29:23 -0400 Subject: [PATCH 4/5] Update packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts Co-authored-by: Adam Brauer <400763+ambrauer@users.noreply.github.com> --- .../src/middleware/personalize-middleware.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts index 6ee6bf2978..464dafb54c 100644 --- a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts +++ b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts @@ -263,13 +263,7 @@ export class PersonalizeMiddleware extends MiddlewareBase { // Restore cookies from previous response since // browserId cookie gets omitted after rewrite cookies.forEach((cookie) => { - response.cookies.set(cookie.name, cookie.value, { - domain: cookie.domain, - expires: cookie.expires, - maxAge: cookie.maxAge, - sameSite: cookie.sameSite, - secure: cookie.secure, - }); + response.cookies.set(cookie); }); debug.personalize('personalize middleware end in %dms: %o', Date.now() - startTimestamp, { From 4391fbcf97c8a0164c397efd4dedd8a0e0495c05 Mon Sep 17 00:00:00 2001 From: Addy Pathania Date: Tue, 17 Oct 2023 09:28:58 -0400 Subject: [PATCH 5/5] fix test related to cookies --- .../src/middleware/personalize-middleware.test.ts | 5 ++++- .../src/middleware/personalize-middleware.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.test.ts b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.test.ts index d46e9cee51..20a9e6a1b1 100644 --- a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.test.ts +++ b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.test.ts @@ -114,6 +114,9 @@ describe('PersonalizeMiddleware', () => { get(key) { return { value: res.cookies[key] }; }, + getAll() { + return Object.keys(res.cookies).map((key) => ({ name: key, value: res.cookies[key] })); + }, ...props.cookieValues, }, headers: { @@ -799,7 +802,7 @@ describe('PersonalizeMiddleware', () => { const finalRes = await middleware.getHandler()(req, res); - expect(engageServer.called).to.be.true; + expect(engageServer.called).to.be.false; expect(getPersonalizeInfo.called).to.be.true; expect(errorSpy.getCall(0).calledWith('Personalize middleware failed:')).to.be.true; diff --git a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts index 464dafb54c..03601daab8 100644 --- a/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts +++ b/packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts @@ -245,7 +245,7 @@ export class PersonalizeMiddleware extends MiddlewareBase { const rewritePath = getPersonalizedRewrite(basePath, { variantId }); // Note an absolute URL is required: https://nextjs.org/docs/messages/middleware-relative-urls const rewriteUrl = req.nextUrl.clone(); - + // Preserve cookies from previous response const cookies = response.cookies.getAll(); @@ -260,7 +260,7 @@ export class PersonalizeMiddleware extends MiddlewareBase { // Share site name with the following executed middlewares response.cookies.set(this.SITE_SYMBOL, site.name); - // Restore cookies from previous response since + // Restore cookies from previous response since // browserId cookie gets omitted after rewrite cookies.forEach((cookie) => { response.cookies.set(cookie);