diff --git a/packages/nextjs/src/proxy/redirects-proxy.test.ts b/packages/nextjs/src/proxy/redirects-proxy.test.ts index 507cee9a9c..bd8b4849a4 100644 --- a/packages/nextjs/src/proxy/redirects-proxy.test.ts +++ b/packages/nextjs/src/proxy/redirects-proxy.test.ts @@ -12,7 +12,7 @@ import { } from '@sitecore-content-sdk/content/site'; import chai, { use } from 'chai'; import chaiString from 'chai-string'; -import { NextRequest, NextResponse } from 'next/server'; +import nextjs, { NextRequest, NextResponse } from 'next/server'; import sinon, { spy } from 'sinon'; import sinonChai from 'sinon-chai'; import { RedirectsProxy, RedirectsProxyConfig } from './redirects-proxy'; @@ -48,6 +48,7 @@ describe('RedirectsProxy', () => { let nextRedirectStub: sinon.SinonStub; let nextRewriteStub: sinon.SinonStub; + let afterStub: sinon.SinonStub; const sandbox = sinon.createSandbox(); @@ -314,12 +315,14 @@ describe('RedirectsProxy', () => { before(() => { nextRedirectStub = sandbox.stub(NextResponse, 'redirect'); nextRewriteStub = sandbox.stub(NextResponse, 'rewrite'); + afterStub = sandbox.stub(nextjs, 'after'); }); beforeEach(() => { debugSpy.resetHistory(); nextRedirectStub.reset(); nextRewriteStub.reset(); + afterStub.reset(); // Reset the stubs to return undefined by default, tests will override nextRedirectStub.returns(undefined); nextRewriteStub.returns(undefined); @@ -328,6 +331,7 @@ describe('RedirectsProxy', () => { after(() => { nextRedirectStub.restore(); nextRewriteStub.restore(); + afterStub.restore(); }); describe('request skipped', () => { @@ -924,6 +928,35 @@ describe('RedirectsProxy', () => { expect(finalRes.redirected).to.be.true; expect(finalRes.status).to.equal(301); }); + + it('should call redirectHandled callback if provided for', async () => { + const req = createRequest(); + const res = createResponse(); + + const redirectHandled = sandbox.stub(); + const { proxy } = createProxy({ + redirectsProxyConfig: { redirectHandled }, + target: 'https://example.com/new-page', + }); + + afterStub.callsFake((callback) => { + if (typeof callback === 'function') { + callback(); + } + }); + + await proxy.handle(req, res); + + const firstArg = redirectHandled.getCall(0).args[0]; + const secondArg = redirectHandled.getCall(0).args[1]; + expect(redirectHandled.calledOnce).to.be.true; + expect(firstArg).to.deep.equal(req); + expect(secondArg).to.deep.equal({ + target: 'https://example.com/new-page', + type: REDIRECT_TYPE_301, + isExternal: true, + }); + }); }); describe('error handling', () => { diff --git a/packages/nextjs/src/proxy/redirects-proxy.ts b/packages/nextjs/src/proxy/redirects-proxy.ts index 98201e61a0..b9b79f71c6 100644 --- a/packages/nextjs/src/proxy/redirects-proxy.ts +++ b/packages/nextjs/src/proxy/redirects-proxy.ts @@ -14,7 +14,7 @@ import { mergeURLSearchParams, } from '@sitecore-content-sdk/core/tools'; import { NextURL } from 'next/dist/server/web/next-url'; -import { NextRequest, NextResponse } from 'next/server'; +import { after, NextRequest, NextResponse } from 'next/server'; import regexParser from 'regex-parser'; import { ProxyBase, ProxyBaseConfig, REWRITE_HEADER_NAME } from './proxy'; import { SitecoreConfig } from '../config'; @@ -25,6 +25,12 @@ const REGEXP_ABSOLUTE_URL = new RegExp('^(?:[a-z]+:)?//', 'i'); type RedirectResult = RedirectInfo & { matchedQueryString?: string }; +type HandledRedirectInfo = { + target: NextURL | string; + type: string; + isExternal: boolean; +}; + /** * The interface for the RedirectsProxy configuration. * @public @@ -35,6 +41,7 @@ export type RedirectsProxyConfig = Omit Promise | void; }; /** * Proxy / handler fetches all redirects from Sitecore instance by grapqhl service @@ -440,6 +447,11 @@ export class RedirectsProxy extends ProxyBase { res: NextResponse, isExternal = false ): NextResponse { + if (this.config.redirectHandled) { + const redirectHandled = this.config.redirectHandled; + after(() => redirectHandled(req, { target, type, isExternal })); + } + switch (type) { case REDIRECT_TYPE_301: return this.createRedirectResponse(target, res, 301, 'Moved Permanently');