@sitecore-content-sdk/nextjs 1.5.0 → 2.0.0-canary.10
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/dist/cjs/client/index.js +1 -1
- package/dist/cjs/client/sitecore-nextjs-client.js +4 -4
- package/dist/cjs/components/BYOCWrapper.js +0 -5
- package/dist/cjs/components/FEaaSWrapper.js +0 -5
- package/dist/cjs/components/NextImage.js +2 -2
- package/dist/cjs/config/define-config.js +7 -4
- package/dist/cjs/config-cli/define-cli-config.js +1 -1
- package/dist/cjs/debug.js +11 -0
- package/dist/cjs/editing/codegen/import-map-server.js +1 -1
- package/dist/cjs/editing/editing-config-middleware.js +13 -11
- package/dist/cjs/editing/editing-render-middleware.js +41 -29
- package/dist/cjs/editing/feaas-render-middleware.js +24 -13
- package/dist/cjs/editing/index.js +2 -2
- package/dist/cjs/editing/types.js +2 -0
- package/dist/cjs/editing/utils.js +35 -6
- package/dist/cjs/index.js +17 -11
- package/dist/cjs/middleware/index.js +1 -24
- package/dist/cjs/{middleware/app-router-multisite-middleware.js → proxy/app-router-multisite-proxy.js} +8 -8
- package/dist/cjs/proxy/index.js +29 -0
- package/dist/cjs/{middleware/locale-middleware.js → proxy/locale-proxy.js} +18 -15
- package/dist/cjs/{middleware/multisite-middleware.js → proxy/multisite-proxy.js} +23 -20
- package/dist/cjs/{middleware/personalize-middleware.js → proxy/personalize-proxy.js} +31 -28
- package/dist/cjs/{middleware/middleware.js → proxy/proxy.js} +31 -28
- package/dist/cjs/{middleware/redirects-middleware.js → proxy/redirects-proxy.js} +121 -111
- package/dist/cjs/route-handler/editing-config-route-handler.js +16 -13
- package/dist/cjs/route-handler/editing-render-route-handler.js +43 -32
- package/dist/cjs/route-handler/robots-route-handler.js +14 -6
- package/dist/cjs/route-handler/sitemap-route-handler.js +13 -5
- package/dist/cjs/site/index.js +1 -1
- package/dist/cjs/tools/codegen/import-map.js +2 -2
- package/dist/cjs/tools/generate-map.js +1 -1
- package/dist/cjs/tools/index.js +7 -8
- package/dist/cjs/tools/templating/byoc-component.js +1 -1
- package/dist/cjs/tools/templating/default-component.js +1 -1
- package/dist/cjs/tools/templating/utils.js +5 -6
- package/dist/cjs/utils/index.js +4 -5
- package/dist/cjs/utils/utils.js +3 -3
- package/dist/esm/client/index.js +1 -1
- package/dist/esm/client/sitecore-nextjs-client.js +4 -4
- package/dist/esm/components/BYOCWrapper.js +0 -5
- package/dist/esm/components/FEaaSWrapper.js +0 -5
- package/dist/esm/components/NextImage.js +2 -2
- package/dist/esm/config/define-config.js +7 -4
- package/dist/esm/config-cli/define-cli-config.js +1 -1
- package/dist/esm/debug.js +9 -0
- package/dist/esm/editing/codegen/import-map-server.js +1 -1
- package/dist/esm/editing/editing-config-middleware.js +4 -5
- package/dist/esm/editing/editing-render-middleware.js +22 -13
- package/dist/esm/editing/feaas-render-middleware.js +14 -6
- package/dist/esm/editing/index.js +2 -2
- package/dist/esm/editing/types.js +1 -0
- package/dist/esm/editing/utils.js +32 -4
- package/dist/esm/index.js +11 -12
- package/dist/esm/middleware/index.js +0 -9
- package/dist/esm/{middleware/app-router-multisite-middleware.js → proxy/app-router-multisite-proxy.js} +6 -6
- package/dist/esm/proxy/index.js +9 -0
- package/dist/esm/{middleware/locale-middleware.js → proxy/locale-proxy.js} +12 -12
- package/dist/esm/{middleware/multisite-middleware.js → proxy/multisite-proxy.js} +16 -16
- package/dist/esm/{middleware/personalize-middleware.js → proxy/personalize-proxy.js} +17 -17
- package/dist/esm/{middleware/middleware.js → proxy/proxy.js} +24 -24
- package/dist/esm/{middleware/redirects-middleware.js → proxy/redirects-proxy.js} +112 -102
- package/dist/esm/route-handler/editing-config-route-handler.js +4 -4
- package/dist/esm/route-handler/editing-render-route-handler.js +19 -11
- package/dist/esm/route-handler/robots-route-handler.js +8 -3
- package/dist/esm/route-handler/sitemap-route-handler.js +8 -3
- package/dist/esm/site/index.js +1 -1
- package/dist/esm/tools/codegen/import-map.js +1 -1
- package/dist/esm/tools/generate-map.js +1 -1
- package/dist/esm/tools/index.js +2 -1
- package/dist/esm/tools/templating/byoc-component.js +1 -1
- package/dist/esm/tools/templating/default-component.js +1 -1
- package/dist/esm/tools/templating/utils.js +1 -2
- package/dist/esm/utils/index.js +2 -2
- package/dist/esm/utils/utils.js +2 -2
- package/package.json +187 -181
- package/proxy.d.ts +1 -0
- package/types/client/index.d.ts +1 -1
- package/types/client/index.d.ts.map +1 -1
- package/types/client/sitecore-nextjs-client.d.ts +3 -3
- package/types/client/sitecore-nextjs-client.d.ts.map +1 -1
- package/types/components/BYOCWrapper.d.ts +0 -5
- package/types/components/BYOCWrapper.d.ts.map +1 -1
- package/types/components/FEaaSWrapper.d.ts +0 -5
- package/types/components/FEaaSWrapper.d.ts.map +1 -1
- package/types/components/Placeholder.d.ts +2 -2
- package/types/components/Placeholder.d.ts.map +1 -1
- package/types/config/define-config.d.ts +1 -1
- package/types/config/define-config.d.ts.map +1 -1
- package/types/config-cli/define-cli-config.d.ts +1 -1
- package/types/config-cli/define-cli-config.d.ts.map +1 -1
- package/types/debug.d.ts +7 -0
- package/types/debug.d.ts.map +1 -0
- package/types/editing/codegen/import-map-server.d.ts +1 -1
- package/types/editing/codegen/import-map-server.d.ts.map +1 -1
- package/types/editing/codegen/import-map-utils.d.ts +1 -1
- package/types/editing/codegen/import-map-utils.d.ts.map +1 -1
- package/types/editing/codegen/import-map.d.ts +1 -1
- package/types/editing/codegen/import-map.d.ts.map +1 -1
- package/types/editing/codegen/index.d.ts +1 -1
- package/types/editing/codegen/index.d.ts.map +1 -1
- package/types/editing/editing-config-middleware.d.ts +1 -1
- package/types/editing/editing-config-middleware.d.ts.map +1 -1
- package/types/editing/editing-render-middleware.d.ts +8 -1
- package/types/editing/editing-render-middleware.d.ts.map +1 -1
- package/types/editing/feaas-render-middleware.d.ts +1 -1
- package/types/editing/feaas-render-middleware.d.ts.map +1 -1
- package/types/editing/index.d.ts +3 -2
- package/types/editing/index.d.ts.map +1 -1
- package/types/editing/types.d.ts +37 -0
- package/types/editing/types.d.ts.map +1 -0
- package/types/editing/utils.d.ts +12 -1
- package/types/editing/utils.d.ts.map +1 -1
- package/types/index.d.ts +13 -11
- package/types/index.d.ts.map +1 -1
- package/types/middleware/index.d.ts +0 -9
- package/types/middleware/index.d.ts.map +1 -1
- package/types/middleware/robots-middleware.d.ts +1 -1
- package/types/middleware/robots-middleware.d.ts.map +1 -1
- package/types/middleware/sitemap-middleware.d.ts +1 -1
- package/types/middleware/sitemap-middleware.d.ts.map +1 -1
- package/types/{middleware/app-router-multisite-middleware.d.ts → proxy/app-router-multisite-proxy.d.ts} +6 -6
- package/types/proxy/app-router-multisite-proxy.d.ts.map +1 -0
- package/types/proxy/index.d.ts +10 -0
- package/types/proxy/index.d.ts.map +1 -0
- package/types/proxy/locale-proxy.d.ts +35 -0
- package/types/proxy/locale-proxy.d.ts.map +1 -0
- package/types/{middleware/multisite-middleware.d.ts → proxy/multisite-proxy.d.ts} +11 -11
- package/types/proxy/multisite-proxy.d.ts.map +1 -0
- package/types/{middleware/personalize-middleware.d.ts → proxy/personalize-proxy.d.ts} +10 -10
- package/types/proxy/personalize-proxy.d.ts.map +1 -0
- package/types/{middleware/middleware.d.ts → proxy/proxy.d.ts} +24 -26
- package/types/proxy/proxy.d.ts.map +1 -0
- package/types/{middleware/redirects-middleware.d.ts → proxy/redirects-proxy.d.ts} +11 -11
- package/types/proxy/redirects-proxy.d.ts.map +1 -0
- package/types/route-handler/editing-config-route-handler.d.ts +1 -1
- package/types/route-handler/editing-config-route-handler.d.ts.map +1 -1
- package/types/route-handler/editing-render-route-handler.d.ts +7 -0
- package/types/route-handler/editing-render-route-handler.d.ts.map +1 -1
- package/types/route-handler/robots-route-handler.d.ts +2 -2
- package/types/route-handler/robots-route-handler.d.ts.map +1 -1
- package/types/route-handler/sitemap-route-handler.d.ts +2 -2
- package/types/route-handler/sitemap-route-handler.d.ts.map +1 -1
- package/types/services/component-props-service.d.ts +1 -1
- package/types/services/component-props-service.d.ts.map +1 -1
- package/types/sharedTypes/component-props.d.ts +1 -1
- package/types/sharedTypes/component-props.d.ts.map +1 -1
- package/types/sharedTypes/sitecore-page-props.d.ts +2 -2
- package/types/sharedTypes/sitecore-page-props.d.ts.map +1 -1
- package/types/site/index.d.ts +1 -1
- package/types/site/index.d.ts.map +1 -1
- package/types/tools/codegen/import-map.d.ts +3 -3
- package/types/tools/codegen/import-map.d.ts.map +1 -1
- package/types/tools/generate-map.d.ts +1 -1
- package/types/tools/generate-map.d.ts.map +1 -1
- package/types/tools/index.d.ts +3 -1
- package/types/tools/index.d.ts.map +1 -1
- package/types/tools/templating/byoc-component.d.ts +1 -1
- package/types/tools/templating/byoc-component.d.ts.map +1 -1
- package/types/tools/templating/default-component.d.ts +1 -1
- package/types/tools/templating/default-component.d.ts.map +1 -1
- package/types/tools/templating/utils.d.ts +2 -2
- package/types/tools/templating/utils.d.ts.map +1 -1
- package/types/utils/index.d.ts +2 -2
- package/types/utils/index.d.ts.map +1 -1
- package/types/middleware/app-router-multisite-middleware.d.ts.map +0 -1
- package/types/middleware/locale-middleware.d.ts +0 -35
- package/types/middleware/locale-middleware.d.ts.map +0 -1
- package/types/middleware/middleware.d.ts.map +0 -1
- package/types/middleware/multisite-middleware.d.ts.map +0 -1
- package/types/middleware/personalize-middleware.d.ts.map +0 -1
- package/types/middleware/redirects-middleware.d.ts.map +0 -1
|
@@ -7,30 +7,29 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { areURLSearchParamsEqual, escapeNonSpecialQuestionMarks, isRegexOrUrl, mergeURLSearchParams, } from '@sitecore-content-sdk/core/utils';
|
|
10
|
+
import { RedirectsService, REDIRECT_TYPE_301, REDIRECT_TYPE_302, REDIRECT_TYPE_SERVER_TRANSFER, } from '@sitecore-content-sdk/content/site';
|
|
11
|
+
import { areURLSearchParamsEqual, escapeNonSpecialQuestionMarks, isRegexOrUrl, mergeURLSearchParams, } from '@sitecore-content-sdk/core/tools';
|
|
13
12
|
import { NextResponse } from 'next/server';
|
|
14
13
|
import regexParser from 'regex-parser';
|
|
15
|
-
import {
|
|
14
|
+
import { ProxyBase, REWRITE_HEADER_NAME } from './proxy';
|
|
15
|
+
import debug from '../debug';
|
|
16
16
|
const REGEXP_CONTEXT_SITE_LANG = new RegExp(/\$siteLang/, 'i');
|
|
17
17
|
const REGEXP_ABSOLUTE_URL = new RegExp('^(?:[a-z]+:)?//', 'i');
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Proxy / handler fetches all redirects from Sitecore instance by grapqhl service
|
|
20
20
|
* compares with current url and redirects to target url
|
|
21
21
|
* @public
|
|
22
22
|
*/
|
|
23
|
-
export class
|
|
23
|
+
export class RedirectsProxy extends ProxyBase {
|
|
24
24
|
/**
|
|
25
|
-
* @param {
|
|
25
|
+
* @param {RedirectsProxyConfig} [config] redirects proxy config
|
|
26
26
|
*/
|
|
27
27
|
constructor(config) {
|
|
28
|
-
var _a;
|
|
29
28
|
super(config);
|
|
30
29
|
this.config = config;
|
|
31
30
|
this.handle = (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
32
31
|
if (!this.config.enabled) {
|
|
33
|
-
debug.redirects('skipped (redirects
|
|
32
|
+
debug.redirects('skipped (redirects proxy is disabled globally)');
|
|
34
33
|
return res;
|
|
35
34
|
}
|
|
36
35
|
try {
|
|
@@ -39,124 +38,133 @@ export class RedirectsMiddleware extends MiddlewareBase {
|
|
|
39
38
|
const hostname = this.getHostHeader(req) || this.defaultHostname;
|
|
40
39
|
let site;
|
|
41
40
|
const startTimestamp = Date.now();
|
|
42
|
-
debug.redirects('redirects
|
|
41
|
+
debug.redirects('redirects proxy start: %o', {
|
|
43
42
|
pathname,
|
|
44
43
|
language,
|
|
45
44
|
hostname,
|
|
46
45
|
});
|
|
47
46
|
if (this.disabled(req, res)) {
|
|
48
|
-
debug.redirects('skipped (redirects
|
|
47
|
+
debug.redirects('skipped (redirects proxy is disabled)');
|
|
49
48
|
return res;
|
|
50
49
|
}
|
|
51
50
|
const isAppRouterRequest = this.isAppRouter(res);
|
|
52
|
-
const
|
|
53
|
-
var _a;
|
|
51
|
+
const validateRequest = () => {
|
|
54
52
|
if (this.isPreview(req)) {
|
|
55
53
|
debug.redirects('skipped (preview)');
|
|
56
|
-
return
|
|
54
|
+
return false;
|
|
57
55
|
}
|
|
58
56
|
// Skip prefetch requests from Next.js, which are not original client requests
|
|
59
|
-
// as they load unnecessary requests that burden the redirects
|
|
57
|
+
// as they load unnecessary requests that burden the redirects proxy with meaningless traffic
|
|
60
58
|
if (this.isPrefetch(req)) {
|
|
61
59
|
debug.redirects('skipped (prefetch)');
|
|
62
|
-
res.headers.set('x-
|
|
60
|
+
res.headers.set('x-proxy-cache', 'no-cache');
|
|
63
61
|
res.headers.set('Cache-Control', 'no-store, must-revalidate');
|
|
64
|
-
return
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
};
|
|
66
|
+
if (!validateRequest()) {
|
|
67
|
+
return res;
|
|
68
|
+
}
|
|
69
|
+
site = this.getSite(req, res);
|
|
70
|
+
// Find the redirect from result of RedirectService
|
|
71
|
+
const existsRedirect = yield this.getExistsRedirect(req, site.name);
|
|
72
|
+
if (!existsRedirect) {
|
|
73
|
+
debug.redirects('skipped (redirect does not exist)');
|
|
74
|
+
return res;
|
|
75
|
+
}
|
|
76
|
+
debug.redirects('Matched redirect rule: %o', { existsRedirect });
|
|
77
|
+
const processAbsoluteUrlTarget = (url, existsRedirect) => {
|
|
78
|
+
var _a;
|
|
79
|
+
// Redirect logic for absolute (external or not) URLS. To avoid locale stripping: use plain string for external URLs to prevent Next.js rewriting.
|
|
80
|
+
let targetUrl = existsRedirect.target;
|
|
81
|
+
if (url.search && existsRedirect.isQueryStringPreserved) {
|
|
82
|
+
const incomingQS = new URLSearchParams((_a = url.search) !== null && _a !== void 0 ? _a : '');
|
|
83
|
+
const [targetMainUrl, targetQS] = targetUrl.split('?');
|
|
84
|
+
const mergedQueryString = mergeURLSearchParams(incomingQS, new URLSearchParams(targetQS || ''));
|
|
85
|
+
targetUrl = `${targetMainUrl}?${mergedQueryString}`;
|
|
65
86
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
return this.dispatchRedirect(targetUrl, existsRedirect.redirectType, req, res, true);
|
|
88
|
+
};
|
|
89
|
+
const processRelativeUrlTarget = (url, existsRedirect) => {
|
|
90
|
+
var _a;
|
|
91
|
+
let targetUrl = existsRedirect.target;
|
|
92
|
+
const possiblyLocalePrefix = targetUrl.split('/')[1];
|
|
93
|
+
let targetLocale = '';
|
|
94
|
+
if (this.locales.includes(possiblyLocalePrefix)) {
|
|
95
|
+
targetLocale = possiblyLocalePrefix;
|
|
96
|
+
targetUrl = targetUrl.replace(`/${possiblyLocalePrefix}`, '');
|
|
72
97
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (REGEXP_CONTEXT_SITE_LANG.test(existsRedirect.target) &&
|
|
76
|
-
!(REGEXP_ABSOLUTE_URL.test(existsRedirect.target) &&
|
|
77
|
-
existsRedirect.target.includes(hostname))) {
|
|
78
|
-
existsRedirect.target = existsRedirect.target.replace(REGEXP_CONTEXT_SITE_LANG, site.language);
|
|
79
|
-
if (!isAppRouterRequest) {
|
|
80
|
-
req.nextUrl.locale = site.language;
|
|
81
|
-
}
|
|
98
|
+
else if (existsRedirect.isLanguagePreserved) {
|
|
99
|
+
targetLocale = language;
|
|
82
100
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
let [targetMainUrl, targetQS] = targetUrl.split('?');
|
|
102
|
+
if (url.search && existsRedirect.isQueryStringPreserved) {
|
|
103
|
+
const incomingQS = new URLSearchParams((_a = url.search) !== null && _a !== void 0 ? _a : '');
|
|
104
|
+
targetQS = mergeURLSearchParams(incomingQS, new URLSearchParams(targetQS || ''));
|
|
105
|
+
}
|
|
106
|
+
const prepareNewURL = new URL(`${targetMainUrl}${targetQS ? '?' + targetQS : ''}`, url.origin);
|
|
107
|
+
const basePath = url.basePath; // setting NextUrl.href overrides basePath, so we need to store it
|
|
108
|
+
url.href = prepareNewURL.href;
|
|
109
|
+
url.pathname = prepareNewURL.pathname;
|
|
110
|
+
url.search = prepareNewURL.search;
|
|
111
|
+
// NextUrl setter sets '/' by default if basePath is empty
|
|
112
|
+
// this causes issues when basePath is not configured so we need to set it only if exists
|
|
113
|
+
if (basePath) {
|
|
114
|
+
url.basePath = basePath;
|
|
115
|
+
}
|
|
116
|
+
if (!isAppRouterRequest) {
|
|
117
|
+
// for pages router i18n implementation, apply default locale as backup
|
|
118
|
+
url.locale = targetLocale || req.nextUrl.defaultLocale || 'en';
|
|
99
119
|
}
|
|
100
120
|
else {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (this.locales.includes(urlFirstPart)) {
|
|
105
|
-
if (!isAppRouterRequest) {
|
|
106
|
-
req.nextUrl.locale = urlFirstPart;
|
|
107
|
-
}
|
|
108
|
-
existsRedirect.target = existsRedirect.target.replace(`/${urlFirstPart}`, '');
|
|
109
|
-
}
|
|
110
|
-
const targetSegments = isUrl
|
|
111
|
-
? existsRedirect.target.split('?')
|
|
112
|
-
: url.pathname.replace(/\/*$/gi, '') + existsRedirect.matchedQueryString;
|
|
113
|
-
const [targetPath, targetQueryString] = isUrl
|
|
114
|
-
? targetSegments
|
|
115
|
-
: targetSegments
|
|
116
|
-
.replace(regexParser(existsRedirect.pattern), existsRedirect.target)
|
|
117
|
-
.replace(/^\/\//, '/')
|
|
118
|
-
.split('?');
|
|
119
|
-
const mergedQueryString = existsRedirect.isQueryStringPreserved
|
|
120
|
-
? mergeURLSearchParams(new URLSearchParams((_a = url.search) !== null && _a !== void 0 ? _a : ''), new URLSearchParams(targetQueryString || ''))
|
|
121
|
-
: targetQueryString || '';
|
|
122
|
-
const prepareNewURL = new URL(`${targetPath}${mergedQueryString ? '?' + mergedQueryString : ''}`, url.origin);
|
|
123
|
-
const basePath = url.basePath; // setting NextUrl.href overrides basePath, so we need to store it
|
|
124
|
-
url.href = prepareNewURL.href;
|
|
125
|
-
url.pathname = prepareNewURL.pathname;
|
|
126
|
-
url.search = prepareNewURL.search;
|
|
127
|
-
// NextUrl setter sets '/' by default if basePath is empty
|
|
128
|
-
// this causes issues when basePath is not configured so we need to set it only if exists
|
|
129
|
-
if (basePath) {
|
|
130
|
-
url.basePath = basePath;
|
|
131
|
-
}
|
|
132
|
-
if (!isAppRouterRequest) {
|
|
133
|
-
url.locale = req.nextUrl.locale;
|
|
134
|
-
}
|
|
121
|
+
// In App Router, we need to set the locale in the pathname, if present
|
|
122
|
+
if (targetLocale)
|
|
123
|
+
url.pathname = `/${targetLocale}${url.pathname}`;
|
|
135
124
|
}
|
|
136
125
|
/** return Response redirect with http code of redirect type */
|
|
137
|
-
return this.dispatchRedirect(url, existsRedirect.redirectType, req, res, false);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
126
|
+
return this.dispatchRedirect(this.normalizeUrl(url), existsRedirect.redirectType, req, res, false);
|
|
127
|
+
};
|
|
128
|
+
// replace $siteLang token in target if exists
|
|
129
|
+
existsRedirect.target = existsRedirect.target.replace(REGEXP_CONTEXT_SITE_LANG, site.language);
|
|
130
|
+
const reqUrl = this.normalizeUrl(req.nextUrl.clone());
|
|
131
|
+
// Apply regex replacements to the target URL if the pattern is a regex
|
|
132
|
+
const matched = reqUrl.pathname
|
|
133
|
+
.replace(/\/*$/gi, '')
|
|
134
|
+
.match(regexParser(existsRedirect.pattern));
|
|
135
|
+
if (matched) {
|
|
136
|
+
existsRedirect.target = existsRedirect.target.replace(/\$(\d+)/g, (_, index) => {
|
|
137
|
+
return matched[parseInt(index, 10)] || '';
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const redirectedResponse = REGEXP_ABSOLUTE_URL.test(existsRedirect.target)
|
|
141
|
+
? processAbsoluteUrlTarget(reqUrl, existsRedirect)
|
|
142
|
+
: processRelativeUrlTarget(reqUrl, existsRedirect);
|
|
143
|
+
debug.redirects('redirects proxy end in %dms: %o', Date.now() - startTimestamp, {
|
|
144
|
+
redirected: redirectedResponse.redirected,
|
|
145
|
+
status: redirectedResponse.status,
|
|
146
|
+
url: redirectedResponse.url,
|
|
147
|
+
headers: this.extractDebugHeaders(redirectedResponse.headers),
|
|
145
148
|
});
|
|
146
|
-
return
|
|
149
|
+
return redirectedResponse;
|
|
147
150
|
}
|
|
148
151
|
catch (error) {
|
|
149
|
-
console.log('Redirect
|
|
152
|
+
console.log('Redirect proxy failed:');
|
|
150
153
|
console.log(error);
|
|
151
154
|
return res;
|
|
152
155
|
}
|
|
153
156
|
});
|
|
154
157
|
this.locales = config.locales;
|
|
158
|
+
// If redirectsService is provided directly (e.g., for testing), use it
|
|
159
|
+
if (this.config.redirectsService) {
|
|
160
|
+
this.redirectsService = this.config.redirectsService;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
155
163
|
// Validate API config is present - redirects requires either Edge or local API configuration
|
|
156
164
|
const hasEdgeConfig = !!(this.config.contextId || this.config.clientContextId);
|
|
157
165
|
const hasLocalConfig = !!(this.config.apiHost && this.config.apiKey);
|
|
158
166
|
if (!hasEdgeConfig && !hasLocalConfig) {
|
|
159
|
-
console.warn('[
|
|
167
|
+
console.warn('[RedirectsProxy] Redirects proxy requires either Edge configuration (contextId/clientContextId) or local API configuration (apiHost/apiKey). ' +
|
|
160
168
|
'Redirects features will be disabled. This is expected when API configuration is not available.');
|
|
161
169
|
// Set to null to indicate service is disabled
|
|
162
170
|
this.redirectsService = null;
|
|
@@ -179,16 +187,16 @@ export class RedirectsMiddleware extends MiddlewareBase {
|
|
|
179
187
|
};
|
|
180
188
|
// NOTE: we provide native fetch for compatibility on Next.js Edge Runtime
|
|
181
189
|
// (underlying default 'cross-fetch' is not currently compatible: https://github.com/lquixada/cross-fetch/issues/78)
|
|
182
|
-
this.redirectsService =
|
|
183
|
-
(_a = this.config.redirectsService) !== null && _a !== void 0 ? _a : new RedirectsService(Object.assign(Object.assign({}, config), { clientFactory: this.getClientFactory(graphQLOptions), fetch: fetch }));
|
|
190
|
+
this.redirectsService = new RedirectsService(Object.assign(Object.assign({}, config), { clientFactory: this.getClientFactory(graphQLOptions), fetch: fetch }));
|
|
184
191
|
}
|
|
185
192
|
disabled(req, res) {
|
|
186
|
-
// Check if API config is missing - if so, disable the
|
|
193
|
+
// Check if API config is missing - if so, disable the proxy
|
|
187
194
|
if (!this.redirectsService) {
|
|
188
195
|
debug.redirects('skipped (redirects service not configured - API config required)');
|
|
189
196
|
return true;
|
|
190
197
|
}
|
|
191
|
-
|
|
198
|
+
// ignore files
|
|
199
|
+
return req.nextUrl.pathname.includes('.') || super.disabled(req, res);
|
|
192
200
|
}
|
|
193
201
|
/**
|
|
194
202
|
* Method returns RedirectInfo when matches
|
|
@@ -206,7 +214,6 @@ export class RedirectsMiddleware extends MiddlewareBase {
|
|
|
206
214
|
const locale = this.getLanguage(req);
|
|
207
215
|
const normalizedPath = incomingURL.replace(/\/*$/gi, '').toLowerCase();
|
|
208
216
|
const redirects = yield this.redirectsService.fetchRedirects(siteName);
|
|
209
|
-
const language = this.getLanguage(req);
|
|
210
217
|
const modifyRedirects = structuredClone(redirects);
|
|
211
218
|
let matchedQueryString;
|
|
212
219
|
const localePath = `/${locale.toLowerCase()}${normalizedPath}`;
|
|
@@ -233,7 +240,8 @@ export class RedirectsMiddleware extends MiddlewareBase {
|
|
|
233
240
|
// process regex rules
|
|
234
241
|
// Modify the redirect pattern to ignore the language prefix in the path
|
|
235
242
|
// And escapes non-special "?" characters in a string or regex.
|
|
236
|
-
redirect.pattern = escapeNonSpecialQuestionMarks(redirect.pattern.replace(new RegExp(`^[^]?/${
|
|
243
|
+
redirect.pattern = escapeNonSpecialQuestionMarks('^' + redirect.pattern.replace(new RegExp(`^[^]?/${locale}/`, 'gi'), '') // ensure function thinks input is regex
|
|
244
|
+
);
|
|
237
245
|
// Prepare the redirect pattern as a regular expression, making it more flexible for matching URLs
|
|
238
246
|
redirect.pattern = `/^\/${redirect.pattern
|
|
239
247
|
.replace(/^\/|\/$/g, '') // Removes leading and trailing slashes
|
|
@@ -277,7 +285,7 @@ export class RedirectsMiddleware extends MiddlewareBase {
|
|
|
277
285
|
/**
|
|
278
286
|
* Remove special parameters(Next.JS)
|
|
279
287
|
* Example: /about/contact/us
|
|
280
|
-
* When a user clicks on this link, Next.js should generate a link for the
|
|
288
|
+
* When a user clicks on this link, Next.js should generate a link for the proxy, formatted like this:
|
|
281
289
|
* http://host/about/contact/us?path=about&path=contact&path=us
|
|
282
290
|
*/
|
|
283
291
|
const newQueryString = url.search
|
|
@@ -357,7 +365,7 @@ export class RedirectsMiddleware extends MiddlewareBase {
|
|
|
357
365
|
}
|
|
358
366
|
}
|
|
359
367
|
/**
|
|
360
|
-
* Helper function to create a redirect response and remove the x-
|
|
368
|
+
* Helper function to create a redirect response and remove the x-proxy-next header.
|
|
361
369
|
* @param {NextURL | string} url The URL to redirect to.
|
|
362
370
|
* @param {Response} res The response object.
|
|
363
371
|
* @param {number} status The HTTP status code of the redirect.
|
|
@@ -365,7 +373,9 @@ export class RedirectsMiddleware extends MiddlewareBase {
|
|
|
365
373
|
* @returns {NextResponse<unknown>} The redirect response.
|
|
366
374
|
*/
|
|
367
375
|
createRedirectResponse(url, res, status, statusText) {
|
|
368
|
-
|
|
376
|
+
// Convert NextURL to string if needed - NextResponse.redirect requires a string URL
|
|
377
|
+
const urlString = typeof url === 'string' ? url : url.href;
|
|
378
|
+
const redirect = NextResponse.redirect(urlString, {
|
|
369
379
|
status,
|
|
370
380
|
statusText,
|
|
371
381
|
headers: res === null || res === void 0 ? void 0 : res.headers,
|
|
@@ -7,11 +7,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { EDITING_ALLOWED_ORIGINS, QUERY_PARAM_EDITING_SECRET, } from '@sitecore-content-sdk/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { EditMode } from '@sitecore-content-sdk/core/layout';
|
|
10
|
+
import { EDITING_ALLOWED_ORIGINS, QUERY_PARAM_EDITING_SECRET, } from '@sitecore-content-sdk/content/editing';
|
|
11
|
+
import { getEnforcedCorsHeaders } from '@sitecore-content-sdk/core/tools';
|
|
12
|
+
import { EditMode } from '@sitecore-content-sdk/content/layout';
|
|
14
13
|
import { getEditingSecret } from '../utils/utils';
|
|
14
|
+
import debug from '../debug';
|
|
15
15
|
/**
|
|
16
16
|
* Creates a route handler for the editing config API route (e.g. '/api/editing/config')
|
|
17
17
|
* Provides configuration information to determine feature compatibility on Pages side.
|
|
@@ -7,14 +7,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
11
|
-
import { EDITING_ALLOWED_ORIGINS, PREVIEW_KEY, QUERY_PARAM_EDITING_SECRET, INVALID_SECRET_HTML_MESSAGE, } from '@sitecore-content-sdk/
|
|
12
|
-
import { getEnforcedCorsHeaders } from '@sitecore-content-sdk/core/
|
|
13
|
-
import { LayoutServicePageState } from '@sitecore-content-sdk/
|
|
10
|
+
import { NativeDataFetcher } from '@sitecore-content-sdk/core';
|
|
11
|
+
import { EDITING_ALLOWED_ORIGINS, PREVIEW_KEY, QUERY_PARAM_EDITING_SECRET, INVALID_SECRET_HTML_MESSAGE, } from '@sitecore-content-sdk/content/editing';
|
|
12
|
+
import { getEnforcedCorsHeaders } from '@sitecore-content-sdk/core/tools';
|
|
13
|
+
import { LayoutServicePageState } from '@sitecore-content-sdk/content/layout';
|
|
14
14
|
import { getEditingSecret } from '../utils/utils';
|
|
15
15
|
import { draftMode, cookies as nextCokies } from 'next/headers';
|
|
16
|
-
import { mapEditingParams, getEditingRequestHtml, cleanupNextPreviewCookies, getHeadersForPropagation, getQueryParamsForPropagation, getRequiredEditingParamsList, getCSPHeader, resolveServerUrl, } from '../editing/utils';
|
|
17
|
-
import { SITE_KEY } from '@sitecore-content-sdk/
|
|
16
|
+
import { mapEditingParams, getEditingRequestHtml, cleanupNextPreviewCookies, getHeadersForPropagation, getQueryParamsForPropagation, getRequiredEditingParamsList, getCSPHeader, resolveServerUrl, getAllowedQueryParams, } from '../editing/utils';
|
|
17
|
+
import { SITE_KEY } from '@sitecore-content-sdk/content/site';
|
|
18
|
+
import debug from '../debug';
|
|
18
19
|
/**
|
|
19
20
|
* Helper function to handle cookie operations - can be mocked for testing
|
|
20
21
|
* @returns {Promise<NextCookies>} Next cookies
|
|
@@ -108,11 +109,18 @@ export const createEditingRenderRouteHandlers = (options) => {
|
|
|
108
109
|
const mode = query.mode;
|
|
109
110
|
const requiredQueryParams = getRequiredEditingParamsList(mode);
|
|
110
111
|
const missingQueryParams = requiredQueryParams.filter((param) => !query[param]);
|
|
112
|
+
const { allowedQueryParams, missingAllowedParams } = getAllowedQueryParams(query, options.allowedQueryParams);
|
|
111
113
|
// Validate query parameters
|
|
112
|
-
if (missingQueryParams.length) {
|
|
113
|
-
debug.editing('missing required query parameters: %o',
|
|
114
|
+
if (missingQueryParams.length || missingAllowedParams.length) {
|
|
115
|
+
debug.editing('missing required query parameters: %o', [
|
|
116
|
+
...missingQueryParams,
|
|
117
|
+
...missingAllowedParams,
|
|
118
|
+
]);
|
|
114
119
|
return Response.json({
|
|
115
|
-
html: `<html><body>Missing required query parameters: ${
|
|
120
|
+
html: `<html><body>Missing required query parameters: ${[
|
|
121
|
+
...missingQueryParams,
|
|
122
|
+
...missingAllowedParams,
|
|
123
|
+
].join(', ')}</body></html>`,
|
|
116
124
|
}, { status: 400, headers: responseHeaders });
|
|
117
125
|
}
|
|
118
126
|
const encodedRoute = encodeURI(query.route);
|
|
@@ -148,7 +156,7 @@ export const createEditingRenderRouteHandlers = (options) => {
|
|
|
148
156
|
debug.editing('fetching page route for %s', query.route);
|
|
149
157
|
// Get query string parameters to propagate on subsequent requests (e.g. for deployment protection bypass)
|
|
150
158
|
// Additionally ,in app router preview data is passed through query string instead of preview data cookie
|
|
151
|
-
const propagatedQsParams = Object.assign(Object.assign({}, getQueryParamsForPropagation(query)), mapEditingParams(query));
|
|
159
|
+
const propagatedQsParams = Object.assign(Object.assign(Object.assign({}, getQueryParamsForPropagation(query)), mapEditingParams(query)), allowedQueryParams);
|
|
152
160
|
// Get headers to propagate on subsequent requests
|
|
153
161
|
const propagatedHeaders = getHeadersForPropagation(headers);
|
|
154
162
|
const html = yield getEditingRequestHtml(requestUrl, propagatedQsParams, propagatedHeaders, convertedCookies, dataFetcher);
|
|
@@ -207,7 +215,7 @@ export const createEditingRenderRouteHandlers = (options) => {
|
|
|
207
215
|
req.nextUrl.searchParams.forEach((value, key) => {
|
|
208
216
|
query[key] = value;
|
|
209
217
|
});
|
|
210
|
-
const propagatedQsParams = Object.assign(Object.assign({}, getQueryParamsForPropagation(query)), mapEditingParams(query));
|
|
218
|
+
const propagatedQsParams = Object.assign(Object.assign(Object.assign({}, getQueryParamsForPropagation(query)), mapEditingParams(query)), getAllowedQueryParams(query, options.allowedQueryParams).allowedQueryParams);
|
|
211
219
|
const base = resolveServerUrl(req);
|
|
212
220
|
const targetUrl = new URL('/', base);
|
|
213
221
|
for (const key in propagatedQsParams) {
|
|
@@ -7,9 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { SiteResolver } from '@sitecore-content-sdk/
|
|
11
|
-
import { debug } from '@sitecore-content-sdk/core';
|
|
10
|
+
import { SiteResolver } from '@sitecore-content-sdk/content/site';
|
|
12
11
|
import { unstable_cache } from 'next/cache';
|
|
12
|
+
import debug from '../debug';
|
|
13
13
|
/**
|
|
14
14
|
* Creates a route handler to serve the robots.txt file.
|
|
15
15
|
* @param {RouteHandlerOptions} options - The options for the route handler.
|
|
@@ -28,11 +28,12 @@ export const createRobotsRouteHandler = (options) => {
|
|
|
28
28
|
const GET = (req) => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
29
|
var _a;
|
|
30
30
|
try {
|
|
31
|
-
const startTimestamp = Date.now();
|
|
32
31
|
const hostName = req.headers.get('x-forwarded-host') ||
|
|
33
32
|
((_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0]) ||
|
|
34
33
|
'localhost';
|
|
35
34
|
const site = siteResolver.getByHost(hostName);
|
|
35
|
+
// Access request data first, then capture timestamp for Next.js 16 compatibility
|
|
36
|
+
const startTimestamp = Date.now();
|
|
36
37
|
debug.robots('robots route handler start: %o', {
|
|
37
38
|
hostName,
|
|
38
39
|
siteName: site.name,
|
|
@@ -56,6 +57,10 @@ export const createRobotsRouteHandler = (options) => {
|
|
|
56
57
|
});
|
|
57
58
|
}
|
|
58
59
|
catch (error) {
|
|
60
|
+
// Re-throw prerender bail-out errors so Next.js can handle them properly
|
|
61
|
+
if (error instanceof Error && error.digest === 'NEXT_PRERENDER_INTERRUPTED') {
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
59
64
|
console.log('Robots route handler failed:');
|
|
60
65
|
console.log(error);
|
|
61
66
|
return new Response('Internal Server Error', {
|
|
@@ -7,9 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { SiteResolver } from '@sitecore-content-sdk/
|
|
11
|
-
import { debug } from '@sitecore-content-sdk/core';
|
|
10
|
+
import { SiteResolver } from '@sitecore-content-sdk/content/site';
|
|
12
11
|
import { unstable_cache } from 'next/cache';
|
|
12
|
+
import debug from '../debug';
|
|
13
13
|
/**
|
|
14
14
|
* Creates a route handler to serve the sitemap.xml file.
|
|
15
15
|
* @param {RouteHandlerOptions} options - The options for the route handler.
|
|
@@ -35,8 +35,9 @@ export function createSitemapRouteHandler(options) {
|
|
|
35
35
|
});
|
|
36
36
|
const GET = (req) => __awaiter(this, void 0, void 0, function* () {
|
|
37
37
|
try {
|
|
38
|
-
const startTimestamp = Date.now();
|
|
39
38
|
const options = getOptions(req);
|
|
39
|
+
// Access request data first, then capture timestamp for Next.js 16 compatibility
|
|
40
|
+
const startTimestamp = Date.now();
|
|
40
41
|
debug.sitemap('sitemap route handler start: %o', {
|
|
41
42
|
options,
|
|
42
43
|
});
|
|
@@ -49,6 +50,10 @@ export function createSitemapRouteHandler(options) {
|
|
|
49
50
|
});
|
|
50
51
|
}
|
|
51
52
|
catch (error) {
|
|
53
|
+
// Re-throw prerender bail-out errors so Next.js can handle them properly
|
|
54
|
+
if (error instanceof Error && error.digest === 'NEXT_PRERENDER_INTERRUPTED') {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
52
57
|
console.log('Sitemap route handler failed:');
|
|
53
58
|
console.log(error);
|
|
54
59
|
if (error instanceof Error && error.message === 'REDIRECT_404') {
|
package/dist/esm/site/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { SiteResolver } from '@sitecore-content-sdk/
|
|
1
|
+
export { SiteResolver } from '@sitecore-content-sdk/content/site';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeImportMap as writeImportMapCoreImpl, } from '@sitecore-content-sdk/
|
|
1
|
+
import { writeImportMap as writeImportMapCoreImpl, } from '@sitecore-content-sdk/content/node-tools';
|
|
2
2
|
import { detectRouterType, nextjsClientMapTemplate, nextjsServertMapTemplate, nextjsDefaultMapTemplate, } from '../templating/utils';
|
|
3
3
|
let writeImportMapCore = writeImportMapCoreImpl;
|
|
4
4
|
export const __mockDependencies = (mocks) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { filterComponentsByType, } from '@sitecore-content-sdk/
|
|
1
|
+
import { filterComponentsByType, } from '@sitecore-content-sdk/content/tools';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import { detectRouterType, getComponentListWithTypes } from './templating/utils';
|
package/dist/esm/tools/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { generateSites,
|
|
1
|
+
export { generateSites, getComponentList, extractFiles, } from '@sitecore-content-sdk/content/node-tools';
|
|
2
|
+
export { generateMetadata } from '@sitecore-content-sdk/core/node-tools';
|
|
2
3
|
export { generateMap } from './generate-map';
|
|
3
4
|
export { writeImportMap } from './codegen/import-map';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { ComponentTemplateType } from '@sitecore-content-sdk/
|
|
2
|
+
import { ComponentTemplateType } from '@sitecore-content-sdk/content/config';
|
|
3
3
|
import { COMPONENT_FILE_EXTENSION } from './constants';
|
|
4
4
|
/**
|
|
5
5
|
* Next.js BYOC component boilerplate
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { ComponentTemplateType } from '@sitecore-content-sdk/
|
|
2
|
+
import { ComponentTemplateType } from '@sitecore-content-sdk/content/config';
|
|
3
3
|
import { COMPONENT_FILE_EXTENSION } from './constants';
|
|
4
4
|
/**
|
|
5
5
|
* Next.js component boilerplate
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { getComponentList, } from '@sitecore-content-sdk/
|
|
1
|
+
import { getComponentList, defaultImportMapTemplate, } from '@sitecore-content-sdk/content/node-tools';
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
-
import { defaultImportMapTemplate } from '@sitecore-content-sdk/core/tools';
|
|
5
4
|
/**
|
|
6
5
|
* Detects the Next.js router type (App Router or Pages Router) based on directory structure.
|
|
7
6
|
* @param {string} projectRoot - The project root directory. Defaults to current working directory.
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { handleEditorFastRefresh, extractPath, isServerSidePropsContext, parseRewriteHeader, } from './utils';
|
|
2
|
-
export {
|
|
3
|
-
export { isEditorActive, resetEditorChromes } from '@sitecore-content-sdk/
|
|
2
|
+
export { resolveUrl } from '@sitecore-content-sdk/core/tools';
|
|
3
|
+
export { isEditorActive, resetEditorChromes } from '@sitecore-content-sdk/content/editing';
|
package/dist/esm/utils/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isEditorActive, resetEditorChromes } from '@sitecore-content-sdk/
|
|
2
|
-
import { REWRITE_HEADER_NAME } from '../
|
|
1
|
+
import { isEditorActive, resetEditorChromes } from '@sitecore-content-sdk/content/editing';
|
|
2
|
+
import { REWRITE_HEADER_NAME } from '../proxy/proxy';
|
|
3
3
|
/**
|
|
4
4
|
* Since Sitecore editors do not support Fast Refresh:
|
|
5
5
|
* 1. Subscribe on events provided by webpack.
|