@sitecore-content-sdk/nextjs 1.3.0-canary.9 → 1.4.0-canary.2

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.
Files changed (234) hide show
  1. package/README.md +11 -11
  2. package/dist/cjs/client/index.js +10 -10
  3. package/dist/cjs/client/models.js +2 -2
  4. package/dist/cjs/client/sitecore-nextjs-client.js +160 -156
  5. package/dist/cjs/components/BYOCWrapper.js +31 -30
  6. package/dist/cjs/components/ComponentPropsContext.js +66 -59
  7. package/dist/cjs/components/FEaaSWrapper.js +33 -32
  8. package/dist/cjs/components/Link.js +117 -90
  9. package/dist/cjs/components/NextImage.js +66 -62
  10. package/dist/cjs/components/Placeholder.js +55 -50
  11. package/dist/cjs/components/RichText.js +133 -128
  12. package/dist/cjs/config/define-config.js +26 -25
  13. package/dist/cjs/config/index.js +5 -5
  14. package/dist/cjs/config-cli/define-cli-config.js +40 -39
  15. package/dist/cjs/config-cli/index.js +5 -5
  16. package/dist/cjs/editing/codegen/import-map.js +129 -118
  17. package/dist/cjs/editing/codegen/index.js +6 -6
  18. package/dist/cjs/editing/constants.js +10 -10
  19. package/dist/cjs/editing/editing-config-middleware.js +70 -69
  20. package/dist/cjs/editing/editing-render-middleware.js +145 -144
  21. package/dist/cjs/editing/feaas-render-middleware.js +102 -101
  22. package/dist/cjs/editing/index.js +19 -19
  23. package/dist/cjs/editing/render-middleware.js +46 -46
  24. package/dist/cjs/editing/utils.js +260 -257
  25. package/dist/cjs/index.js +132 -131
  26. package/dist/cjs/middleware/app-router-multisite-middleware.js +41 -20
  27. package/dist/cjs/middleware/index.js +30 -30
  28. package/dist/cjs/middleware/locale-middleware.js +85 -84
  29. package/dist/cjs/middleware/middleware.js +195 -192
  30. package/dist/cjs/middleware/multisite-middleware.js +141 -118
  31. package/dist/cjs/middleware/personalize-middleware.js +240 -236
  32. package/dist/cjs/middleware/redirects-middleware.js +323 -297
  33. package/dist/cjs/middleware/robots-middleware.js +45 -44
  34. package/dist/cjs/middleware/sitemap-middleware.js +50 -49
  35. package/dist/cjs/monitoring/healthcheck-middleware.js +31 -30
  36. package/dist/cjs/monitoring/index.js +5 -5
  37. package/dist/cjs/route-handler/editing-config-route-handler.js +110 -106
  38. package/dist/cjs/route-handler/editing-render-route-handler.js +270 -165
  39. package/dist/cjs/route-handler/index.js +11 -11
  40. package/dist/cjs/route-handler/robots-route-handler.js +69 -68
  41. package/dist/cjs/route-handler/sitemap-route-handler.js +66 -65
  42. package/dist/cjs/search/index.js +17 -0
  43. package/dist/cjs/services/component-props-service.js +142 -138
  44. package/dist/cjs/sharedTypes/component-props.js +2 -2
  45. package/dist/cjs/sharedTypes/sitecore-page-props.js +2 -2
  46. package/dist/cjs/site/index.js +5 -5
  47. package/dist/cjs/tools/codegen/import-map.js +15 -0
  48. package/dist/cjs/tools/component-props.loader.js +95 -95
  49. package/dist/cjs/tools/generate-map.js +317 -317
  50. package/dist/cjs/tools/index.js +14 -13
  51. package/dist/cjs/tools/templating/byoc-component.js +36 -36
  52. package/dist/cjs/tools/templating/constants.js +7 -7
  53. package/dist/cjs/tools/templating/default-component.js +35 -35
  54. package/dist/cjs/tools/templating/utils.js +200 -0
  55. package/dist/cjs/utils/index.js +14 -14
  56. package/dist/cjs/utils/utils.js +82 -73
  57. package/dist/esm/client/index.js +2 -2
  58. package/dist/esm/client/models.js +1 -1
  59. package/dist/esm/client/sitecore-nextjs-client.js +156 -152
  60. package/dist/esm/components/BYOCWrapper.js +27 -26
  61. package/dist/esm/components/ComponentPropsContext.js +28 -21
  62. package/dist/esm/components/FEaaSWrapper.js +29 -28
  63. package/dist/esm/components/Link.js +78 -51
  64. package/dist/esm/components/NextImage.js +60 -56
  65. package/dist/esm/components/Placeholder.js +18 -13
  66. package/dist/esm/components/RichText.js +96 -91
  67. package/dist/esm/config/define-config.js +21 -20
  68. package/dist/esm/config/index.js +1 -1
  69. package/dist/esm/config-cli/define-cli-config.js +36 -35
  70. package/dist/esm/config-cli/index.js +1 -1
  71. package/dist/esm/editing/codegen/import-map.js +92 -81
  72. package/dist/esm/editing/codegen/index.js +1 -1
  73. package/dist/esm/editing/constants.js +7 -7
  74. package/dist/esm/editing/editing-config-middleware.js +66 -65
  75. package/dist/esm/editing/editing-render-middleware.js +141 -140
  76. package/dist/esm/editing/feaas-render-middleware.js +98 -97
  77. package/dist/esm/editing/index.js +6 -6
  78. package/dist/esm/editing/render-middleware.js +42 -42
  79. package/dist/esm/editing/utils.js +246 -243
  80. package/dist/esm/index.js +25 -25
  81. package/dist/esm/middleware/app-router-multisite-middleware.js +37 -16
  82. package/dist/esm/middleware/index.js +11 -11
  83. package/dist/esm/middleware/locale-middleware.js +81 -80
  84. package/dist/esm/middleware/middleware.js +189 -186
  85. package/dist/esm/middleware/multisite-middleware.js +137 -114
  86. package/dist/esm/middleware/personalize-middleware.js +236 -232
  87. package/dist/esm/middleware/redirects-middleware.js +316 -290
  88. package/dist/esm/middleware/robots-middleware.js +41 -40
  89. package/dist/esm/middleware/sitemap-middleware.js +46 -45
  90. package/dist/esm/monitoring/healthcheck-middleware.js +27 -26
  91. package/dist/esm/monitoring/index.js +1 -1
  92. package/dist/esm/route-handler/editing-config-route-handler.js +106 -102
  93. package/dist/esm/route-handler/editing-render-route-handler.js +265 -160
  94. package/dist/esm/route-handler/index.js +4 -4
  95. package/dist/esm/route-handler/robots-route-handler.js +65 -64
  96. package/dist/esm/route-handler/sitemap-route-handler.js +63 -62
  97. package/dist/esm/search/index.js +1 -0
  98. package/dist/esm/services/component-props-service.js +135 -131
  99. package/dist/esm/sharedTypes/component-props.js +1 -1
  100. package/dist/esm/sharedTypes/sitecore-page-props.js +1 -1
  101. package/dist/esm/site/index.js +1 -1
  102. package/dist/esm/tools/codegen/import-map.js +11 -0
  103. package/dist/esm/tools/component-props.loader.js +59 -59
  104. package/dist/esm/tools/generate-map.js +279 -279
  105. package/dist/esm/tools/index.js +3 -2
  106. package/dist/esm/tools/templating/byoc-component.js +30 -30
  107. package/dist/esm/tools/templating/constants.js +4 -4
  108. package/dist/esm/tools/templating/default-component.js +29 -29
  109. package/dist/esm/tools/templating/utils.js +190 -0
  110. package/dist/esm/utils/index.js +3 -3
  111. package/dist/esm/utils/utils.js +74 -65
  112. package/package.json +87 -13
  113. package/search.d.ts +1 -0
  114. package/types/client/index.d.ts +3 -2
  115. package/types/client/index.d.ts.map +1 -0
  116. package/types/client/models.d.ts +9 -8
  117. package/types/client/models.d.ts.map +1 -0
  118. package/types/client/sitecore-nextjs-client.d.ts +68 -63
  119. package/types/client/sitecore-nextjs-client.d.ts.map +1 -0
  120. package/types/components/BYOCWrapper.d.ts +16 -14
  121. package/types/components/BYOCWrapper.d.ts.map +1 -0
  122. package/types/components/ComponentPropsContext.d.ts +30 -18
  123. package/types/components/ComponentPropsContext.d.ts.map +1 -0
  124. package/types/components/FEaaSWrapper.d.ts +17 -15
  125. package/types/components/FEaaSWrapper.d.ts.map +1 -0
  126. package/types/components/Link.d.ts +25 -15
  127. package/types/components/Link.d.ts.map +1 -0
  128. package/types/components/NextImage.d.ts +11 -6
  129. package/types/components/NextImage.d.ts.map +1 -0
  130. package/types/components/Placeholder.d.ts +14 -8
  131. package/types/components/Placeholder.d.ts.map +1 -0
  132. package/types/components/RichText.d.ts +35 -25
  133. package/types/components/RichText.d.ts.map +1 -0
  134. package/types/config/define-config.d.ts +42 -38
  135. package/types/config/define-config.d.ts.map +1 -0
  136. package/types/config/index.d.ts +2 -1
  137. package/types/config/index.d.ts.map +1 -0
  138. package/types/config-cli/define-cli-config.d.ts +10 -8
  139. package/types/config-cli/define-cli-config.d.ts.map +1 -0
  140. package/types/config-cli/index.d.ts +2 -1
  141. package/types/config-cli/index.d.ts.map +1 -0
  142. package/types/editing/codegen/import-map.d.ts +15 -3
  143. package/types/editing/codegen/import-map.d.ts.map +1 -0
  144. package/types/editing/codegen/index.d.ts +3 -2
  145. package/types/editing/codegen/index.d.ts.map +1 -0
  146. package/types/editing/constants.d.ts +8 -7
  147. package/types/editing/constants.d.ts.map +1 -0
  148. package/types/editing/editing-config-middleware.d.ts +37 -31
  149. package/types/editing/editing-config-middleware.d.ts.map +1 -0
  150. package/types/editing/editing-render-middleware.d.ts +47 -44
  151. package/types/editing/editing-render-middleware.d.ts.map +1 -0
  152. package/types/editing/feaas-render-middleware.d.ts +35 -32
  153. package/types/editing/feaas-render-middleware.d.ts.map +1 -0
  154. package/types/editing/index.d.ts +7 -6
  155. package/types/editing/index.d.ts.map +1 -0
  156. package/types/editing/render-middleware.d.ts +26 -25
  157. package/types/editing/render-middleware.d.ts.map +1 -0
  158. package/types/editing/utils.d.ts +110 -106
  159. package/types/editing/utils.d.ts.map +1 -0
  160. package/types/index.d.ts +25 -24
  161. package/types/index.d.ts.map +1 -0
  162. package/types/middleware/app-router-multisite-middleware.d.ts +28 -13
  163. package/types/middleware/app-router-multisite-middleware.d.ts.map +1 -0
  164. package/types/middleware/index.d.ts +12 -11
  165. package/types/middleware/index.d.ts.map +1 -0
  166. package/types/middleware/locale-middleware.d.ts +35 -32
  167. package/types/middleware/locale-middleware.d.ts.map +1 -0
  168. package/types/middleware/middleware.d.ts +135 -127
  169. package/types/middleware/middleware.d.ts.map +1 -0
  170. package/types/middleware/multisite-middleware.d.ts +54 -37
  171. package/types/middleware/multisite-middleware.d.ts.map +1 -0
  172. package/types/middleware/personalize-middleware.d.ts +81 -65
  173. package/types/middleware/personalize-middleware.d.ts.map +1 -0
  174. package/types/middleware/redirects-middleware.d.ts +68 -65
  175. package/types/middleware/redirects-middleware.d.ts.map +1 -0
  176. package/types/middleware/robots-middleware.d.ts +15 -13
  177. package/types/middleware/robots-middleware.d.ts.map +1 -0
  178. package/types/middleware/sitemap-middleware.d.ts +16 -14
  179. package/types/middleware/sitemap-middleware.d.ts.map +1 -0
  180. package/types/monitoring/healthcheck-middleware.d.ts +14 -12
  181. package/types/monitoring/healthcheck-middleware.d.ts.map +1 -0
  182. package/types/monitoring/index.d.ts +2 -1
  183. package/types/monitoring/index.d.ts.map +1 -0
  184. package/types/route-handler/editing-config-route-handler.d.ts +30 -24
  185. package/types/route-handler/editing-config-route-handler.d.ts.map +1 -0
  186. package/types/route-handler/editing-render-route-handler.d.ts +33 -25
  187. package/types/route-handler/editing-render-route-handler.d.ts.map +1 -0
  188. package/types/route-handler/index.d.ts +5 -4
  189. package/types/route-handler/index.d.ts.map +1 -0
  190. package/types/route-handler/robots-route-handler.d.ts +30 -28
  191. package/types/route-handler/robots-route-handler.d.ts.map +1 -0
  192. package/types/route-handler/sitemap-route-handler.d.ts +30 -28
  193. package/types/route-handler/sitemap-route-handler.d.ts.map +1 -0
  194. package/types/search/index.d.ts +2 -0
  195. package/types/search/index.d.ts.map +1 -0
  196. package/types/services/component-props-service.d.ts +62 -57
  197. package/types/services/component-props-service.d.ts.map +1 -0
  198. package/types/sharedTypes/component-props.d.ts +62 -47
  199. package/types/sharedTypes/component-props.d.ts.map +1 -0
  200. package/types/sharedTypes/sitecore-page-props.d.ts +14 -9
  201. package/types/sharedTypes/sitecore-page-props.d.ts.map +1 -0
  202. package/types/site/index.d.ts +2 -1
  203. package/types/site/index.d.ts.map +1 -0
  204. package/types/tools/codegen/import-map.d.ts +10 -0
  205. package/types/tools/codegen/import-map.d.ts.map +1 -0
  206. package/types/tools/component-props.loader.d.ts +8 -7
  207. package/types/tools/component-props.loader.d.ts.map +1 -0
  208. package/types/tools/generate-map.d.ts +26 -24
  209. package/types/tools/generate-map.d.ts.map +1 -0
  210. package/types/tools/index.d.ts +4 -2
  211. package/types/tools/index.d.ts.map +1 -0
  212. package/types/tools/templating/byoc-component.d.ts +3 -2
  213. package/types/tools/templating/byoc-component.d.ts.map +1 -0
  214. package/types/tools/templating/constants.d.ts +5 -4
  215. package/types/tools/templating/constants.d.ts.map +1 -0
  216. package/types/tools/templating/default-component.d.ts +3 -2
  217. package/types/tools/templating/default-component.d.ts.map +1 -0
  218. package/types/tools/templating/utils.d.ts +44 -0
  219. package/types/tools/templating/utils.d.ts.map +1 -0
  220. package/types/utils/index.d.ts +4 -3
  221. package/types/utils/index.d.ts.map +1 -0
  222. package/types/utils/utils.d.ts +34 -24
  223. package/types/utils/utils.d.ts.map +1 -0
  224. package/client.js +0 -1
  225. package/codegen.js +0 -1
  226. package/config-cli.js +0 -1
  227. package/config.js +0 -1
  228. package/editing.js +0 -1
  229. package/middleware.js +0 -1
  230. package/monitoring.js +0 -1
  231. package/route-handler.js +0 -1
  232. package/site.js +0 -1
  233. package/tools.js +0 -1
  234. package/utils.js +0 -1
@@ -1,160 +1,265 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { debug, NativeDataFetcher } from '@sitecore-content-sdk/core';
11
- import { EDITING_ALLOWED_ORIGINS, PREVIEW_KEY, QUERY_PARAM_EDITING_SECRET, } from '@sitecore-content-sdk/core/editing';
12
- import { getEnforcedCorsHeaders } from '@sitecore-content-sdk/core/utils';
13
- import { LayoutServicePageState } from '@sitecore-content-sdk/core/layout';
14
- import { getEditingSecret } from '../utils/utils';
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/core/site';
18
- /**
19
- * Helper function to handle cookie operations - can be mocked for testing
20
- * @returns {Promise<NextCookies>} Next cookies
21
- */
22
- export function getNextCookies() {
23
- return __awaiter(this, void 0, void 0, function* () {
24
- // In test environment, use mock cookie store only if specifically provided
25
- if (process.env.TEST === 'true' && global.__TEST_COOKIE_STORE__) {
26
- return global.__TEST_COOKIE_STORE__;
27
- }
28
- return yield nextCokies();
29
- });
30
- }
31
- export const createEditingRenderRouteHandlers = (options) => {
32
- const dataFetcher = new NativeDataFetcher({ debugger: debug.editing });
33
- const OPTIONS = (req) => {
34
- var _a;
35
- // init query string values
36
- const query = {};
37
- req.nextUrl.searchParams.forEach((value, key) => {
38
- query[key] = value;
39
- });
40
- const expectedCorsHeaders = getEnforcedCorsHeaders({
41
- requestMethod: req.method,
42
- headers: req.headers,
43
- presetCorsHeader: (_a = req.headers) === null || _a === void 0 ? void 0 : _a.get('Access-Control-Allow-Origin'),
44
- allowedOrigins: EDITING_ALLOWED_ORIGINS,
45
- });
46
- if (!expectedCorsHeaders) {
47
- debug.editing('invalid origin host - set allowed origins in JSS_ALLOWED_ORIGINS environment variable');
48
- return new Response(`<html><body>Requests from origin ${req.headers.get('origin')} not allowed</body></html>`, { status: 401 });
49
- }
50
- debug.editing('preflight request');
51
- return new Response(null, { status: 204, headers: expectedCorsHeaders });
52
- };
53
- const GET = (req) => __awaiter(void 0, void 0, void 0, function* () {
54
- var _a, _b;
55
- const { method, headers } = req;
56
- // init query string values
57
- const query = {};
58
- req.nextUrl.searchParams.forEach((value, key) => {
59
- query[key] = value;
60
- });
61
- debug.editing('editing render handler start: %o', {
62
- method,
63
- query,
64
- headers,
65
- });
66
- const expectedCorsHeaders = getEnforcedCorsHeaders({
67
- requestMethod: req.method,
68
- headers: headers,
69
- presetCorsHeader: headers.get('Access-Control-Allow-Origin'),
70
- allowedOrigins: EDITING_ALLOWED_ORIGINS,
71
- });
72
- if (!expectedCorsHeaders) {
73
- debug.editing('invalid origin host - set allowed origins in JSS_ALLOWED_ORIGINS environment variable');
74
- return new Response(`<html><body>Requests from origin ${req.headers.get('origin')} not allowed</body></html>`, { status: 401 });
75
- }
76
- const responseHeaders = expectedCorsHeaders;
77
- // Validate secret
78
- const secret = query[QUERY_PARAM_EDITING_SECRET];
79
- if (secret !== getEditingSecret()) {
80
- debug.editing('invalid editing secret - sent "%s" expected "%s"', secret, getEditingSecret());
81
- return Response.json({
82
- html: '<html><body>Missing or invalid secret</body></html>',
83
- }, { status: 401, headers: responseHeaders });
84
- }
85
- // enable preview
86
- const draft = yield draftMode();
87
- draft.enable();
88
- const startTimestamp = Date.now();
89
- const mode = query.mode;
90
- const requiredQueryParams = getRequiredEditingParamsList(mode);
91
- const missingQueryParams = requiredQueryParams.filter((param) => !query[param]);
92
- // Validate query parameters
93
- if (missingQueryParams.length) {
94
- debug.editing('missing required query parameters: %o', missingQueryParams);
95
- return Response.json({
96
- html: `<html><body>Missing required query parameters: ${missingQueryParams.join(', ')}</body></html>`,
97
- }, { status: 400, headers: responseHeaders });
98
- }
99
- const encodedRoute = encodeURI(query.route);
100
- const route = ((_a = options === null || options === void 0 ? void 0 : options.resolvePageUrl) === null || _a === void 0 ? void 0 : _a.call(options, encodedRoute)) || encodedRoute;
101
- const base = resolveServerUrl(req);
102
- const requestUrl = new URL(route, base);
103
- // Restrict the page to be rendered only within the allowed origins
104
- responseHeaders['Content-Security-Policy'] = getCSPHeader();
105
- const cookieStore = yield getNextCookies();
106
- cookieStore.set("__prerender_bypass" /* PreviewCookies.PRERENDER_BYPASS */, ((_b = cookieStore.get("__prerender_bypass" /* PreviewCookies.PRERENDER_BYPASS */)) === null || _b === void 0 ? void 0 : _b.value) || '', {
107
- httpOnly: true,
108
- path: '/',
109
- sameSite: 'none',
110
- secure: true,
111
- });
112
- // Set Preview mode identifier cookies, if the page is rendered in Sitecore Preview mode
113
- if (mode === LayoutServicePageState.Preview) {
114
- cookieStore.set(PREVIEW_KEY, 'true', {
115
- httpOnly: true,
116
- path: '/',
117
- sameSite: 'none',
118
- secure: true,
119
- });
120
- cookieStore.set(SITE_KEY, query.sc_site, {
121
- httpOnly: true,
122
- path: '/',
123
- sameSite: 'none',
124
- secure: true,
125
- });
126
- }
127
- const convertedCookies = cookieStore.getAll().map((c) => `${c.name}=${c.value}`);
128
- try {
129
- debug.editing('fetching page route for %s', query.route);
130
- // Get query string parameters to propagate on subsequent requests (e.g. for deployment protection bypass)
131
- // Additionally ,in app router preview data is passed through query string instead of preview data cookie
132
- const propagatedQsParams = Object.assign(Object.assign({}, getQueryParamsForPropagation(query)), mapEditingParams(query));
133
- // Get headers to propagate on subsequent requests
134
- const propagatedHeaders = getHeadersForPropagation(headers);
135
- const html = yield getEditingRequestHtml(requestUrl, propagatedQsParams, propagatedHeaders, convertedCookies, dataFetcher);
136
- // remove nextjs preview cookies to not leak them to the browser
137
- const filteredCookies = cleanupNextPreviewCookies(convertedCookies);
138
- responseHeaders['Set-Cookie'] = (filteredCookies === null || filteredCookies === void 0 ? void 0 : filteredCookies.join('; ')) || '';
139
- debug.editing('editing render handler end in %dms: %o', Date.now() - startTimestamp, {
140
- status: 200,
141
- route,
142
- });
143
- responseHeaders['Content-Type'] = 'text/html; charset=utf-8';
144
- return new Response(html, { status: 200, headers: responseHeaders });
145
- }
146
- catch (err) {
147
- debug.editing('error fetching page route %s: %o', requestUrl, err);
148
- debug.editing('falling back to redirect method... ');
149
- debug.editing('editing render handler end in %dms: redirect %o', Date.now() - startTimestamp, {
150
- status: 307,
151
- route,
152
- });
153
- return Response.redirect(route);
154
- }
155
- finally {
156
- yield draft.disable();
157
- }
158
- });
159
- return { GET, OPTIONS };
160
- };
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { debug, 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/core/editing';
12
+ import { getEnforcedCorsHeaders } from '@sitecore-content-sdk/core/utils';
13
+ import { LayoutServicePageState } from '@sitecore-content-sdk/core/layout';
14
+ import { getEditingSecret } from '../utils/utils';
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/core/site';
18
+ /**
19
+ * Helper function to handle cookie operations - can be mocked for testing
20
+ * @returns {Promise<NextCookies>} Next cookies
21
+ */
22
+ export function getNextCookies() {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ // In test environment, use mock cookie store only if specifically provided
25
+ if (process.env.TEST === 'true' && global.__TEST_COOKIE_STORE__) {
26
+ return global.__TEST_COOKIE_STORE__;
27
+ }
28
+ return yield nextCokies();
29
+ });
30
+ }
31
+ /**
32
+ * Creates a route handler for the editing render API route (e.g. '/api/editing/render')
33
+ * @param {EditingHandlerOptions} options - The options for the route handler.
34
+ * @returns The route handler object with GET and OPTIONS methods.
35
+ * @public
36
+ */
37
+ export const createEditingRenderRouteHandlers = (options) => {
38
+ const dataFetcher = new NativeDataFetcher({ debugger: debug.editing });
39
+ const getCorsHeaders = (req) => {
40
+ var _a;
41
+ const expectedCorsHeaders = getEnforcedCorsHeaders({
42
+ requestMethod: req.method,
43
+ headers: req.headers,
44
+ presetCorsHeader: (_a = req.headers) === null || _a === void 0 ? void 0 : _a.get('Access-Control-Allow-Origin'),
45
+ allowedOrigins: EDITING_ALLOWED_ORIGINS,
46
+ });
47
+ if (!expectedCorsHeaders) {
48
+ debug.editing('invalid origin host - set allowed origins in JSS_ALLOWED_ORIGINS environment variable');
49
+ }
50
+ return expectedCorsHeaders;
51
+ };
52
+ const getOriginNotAllowedMessage = (origin) => {
53
+ return `<html><body>Requests from origin ${origin} not allowed</body></html>`;
54
+ };
55
+ const validateEditingSecret = (receivedSecret) => {
56
+ const editingSecret = getEditingSecret();
57
+ const secretIsvalid = editingSecret === receivedSecret;
58
+ if (!secretIsvalid) {
59
+ debug.editing('invalid editing secret - sent "%s" expected "%s"', receivedSecret, editingSecret);
60
+ }
61
+ return secretIsvalid;
62
+ };
63
+ const OPTIONS = (req) => {
64
+ // init query string values
65
+ const query = {};
66
+ req.nextUrl.searchParams.forEach((value, key) => {
67
+ query[key] = value;
68
+ });
69
+ const expectedCorsHeaders = getCorsHeaders(req);
70
+ if (!expectedCorsHeaders) {
71
+ return new Response(getOriginNotAllowedMessage(req.headers.get('origin') || ''), {
72
+ status: 401,
73
+ });
74
+ }
75
+ debug.editing('preflight request');
76
+ return new Response(null, { status: 204, headers: expectedCorsHeaders });
77
+ };
78
+ const GET = (req) => __awaiter(void 0, void 0, void 0, function* () {
79
+ var _a, _b;
80
+ const { method, headers } = req;
81
+ // init query string values
82
+ const query = {};
83
+ req.nextUrl.searchParams.forEach((value, key) => {
84
+ query[key] = value;
85
+ });
86
+ debug.editing('editing render handler start: %o', {
87
+ method,
88
+ query,
89
+ headers,
90
+ });
91
+ const expectedCorsHeaders = getCorsHeaders(req);
92
+ if (!expectedCorsHeaders) {
93
+ return new Response(getOriginNotAllowedMessage(req.headers.get('origin') || ''), {
94
+ status: 401,
95
+ });
96
+ }
97
+ const responseHeaders = expectedCorsHeaders;
98
+ // Validate secret
99
+ if (!validateEditingSecret(query[QUERY_PARAM_EDITING_SECRET])) {
100
+ return Response.json({
101
+ html: INVALID_SECRET_HTML_MESSAGE,
102
+ }, { status: 401, headers: responseHeaders });
103
+ }
104
+ // enable preview
105
+ const draft = yield draftMode();
106
+ draft.enable();
107
+ const startTimestamp = Date.now();
108
+ const mode = query.mode;
109
+ const requiredQueryParams = getRequiredEditingParamsList(mode);
110
+ const missingQueryParams = requiredQueryParams.filter((param) => !query[param]);
111
+ // Validate query parameters
112
+ if (missingQueryParams.length) {
113
+ debug.editing('missing required query parameters: %o', missingQueryParams);
114
+ return Response.json({
115
+ html: `<html><body>Missing required query parameters: ${missingQueryParams.join(', ')}</body></html>`,
116
+ }, { status: 400, headers: responseHeaders });
117
+ }
118
+ const encodedRoute = encodeURI(query.route);
119
+ const route = ((_a = options === null || options === void 0 ? void 0 : options.resolvePageUrl) === null || _a === void 0 ? void 0 : _a.call(options, encodedRoute)) || encodedRoute;
120
+ const base = resolveServerUrl(req);
121
+ const requestUrl = new URL(route, base);
122
+ // Restrict the page to be rendered only within the allowed origins
123
+ responseHeaders['Content-Security-Policy'] = getCSPHeader();
124
+ const cookieStore = yield getNextCookies();
125
+ cookieStore.set("__prerender_bypass" /* PreviewCookies.PRERENDER_BYPASS */, ((_b = cookieStore.get("__prerender_bypass" /* PreviewCookies.PRERENDER_BYPASS */)) === null || _b === void 0 ? void 0 : _b.value) || '', {
126
+ httpOnly: true,
127
+ path: '/',
128
+ sameSite: 'none',
129
+ secure: true,
130
+ });
131
+ // Set Preview mode identifier cookies, if the page is rendered in Sitecore Preview mode
132
+ if (mode === LayoutServicePageState.Preview) {
133
+ cookieStore.set(PREVIEW_KEY, 'true', {
134
+ httpOnly: true,
135
+ path: '/',
136
+ sameSite: 'none',
137
+ secure: true,
138
+ });
139
+ cookieStore.set(SITE_KEY, query.sc_site, {
140
+ httpOnly: true,
141
+ path: '/',
142
+ sameSite: 'none',
143
+ secure: true,
144
+ });
145
+ }
146
+ const convertedCookies = cookieStore.getAll().map((c) => `${c.name}=${c.value}`);
147
+ try {
148
+ debug.editing('fetching page route for %s', query.route);
149
+ // Get query string parameters to propagate on subsequent requests (e.g. for deployment protection bypass)
150
+ // 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));
152
+ // Get headers to propagate on subsequent requests
153
+ const propagatedHeaders = getHeadersForPropagation(headers);
154
+ const html = yield getEditingRequestHtml(requestUrl, propagatedQsParams, propagatedHeaders, convertedCookies, dataFetcher);
155
+ // remove nextjs preview cookies to not leak them to the browser
156
+ const filteredCookies = cleanupNextPreviewCookies(convertedCookies);
157
+ responseHeaders['Set-Cookie'] = (filteredCookies === null || filteredCookies === void 0 ? void 0 : filteredCookies.join('; ')) || '';
158
+ debug.editing('editing render handler end in %dms: %o', Date.now() - startTimestamp, {
159
+ status: 200,
160
+ route,
161
+ });
162
+ responseHeaders['Content-Type'] = 'text/html; charset=utf-8';
163
+ return new Response(html, { status: 200, headers: responseHeaders });
164
+ }
165
+ catch (err) {
166
+ debug.editing('error fetching page route %s: %o', requestUrl, err);
167
+ debug.editing('falling back to redirect method... ');
168
+ debug.editing('editing render handler end in %dms: redirect %o', Date.now() - startTimestamp, {
169
+ status: 307,
170
+ route,
171
+ });
172
+ return Response.redirect(route);
173
+ }
174
+ finally {
175
+ yield draft.disable();
176
+ }
177
+ });
178
+ /**
179
+ * This POST handler serves as proxy for server action call when Design Library is rendering server component.
180
+ * When Design Library needs to dynamically update or render a generated variant of server component a server action {@link updateServerComponentAction} is called from the client side.
181
+ * The way server functions work is that the action call is made to the same URL with POST method, which in normal page render is handled internally by Next.js.
182
+ * However, in editing mode we are in an api route handler scenario so we need to proxy the POST request to be able to process the server action correctly.
183
+ * @param {NextRequest} req - The incoming request
184
+ */
185
+ const POST = (req) => __awaiter(void 0, void 0, void 0, function* () {
186
+ var _a;
187
+ const requestOrigin = req.headers.get('origin') || '';
188
+ const originHost = new URL(requestOrigin).host;
189
+ const expectedCorsHeaders = getCorsHeaders(req);
190
+ // Bypass CORS if:
191
+ // we are in local or sitecore environment - requested hostname is 'localhost'
192
+ // or the request is same origin (e.g. in vercel netlify environment)
193
+ const bypassCors = req.nextUrl.hostname === 'localhost' || req.nextUrl.host === originHost;
194
+ if (!bypassCors && !expectedCorsHeaders) {
195
+ return new Response(getOriginNotAllowedMessage(requestOrigin), {
196
+ status: 401,
197
+ });
198
+ }
199
+ // Validate secret
200
+ if (!validateEditingSecret(req.nextUrl.searchParams.get(QUERY_PARAM_EDITING_SECRET) || '')) {
201
+ return Response.json({
202
+ html: INVALID_SECRET_HTML_MESSAGE,
203
+ }, { status: 401, headers: expectedCorsHeaders !== null && expectedCorsHeaders !== void 0 ? expectedCorsHeaders : {} });
204
+ }
205
+ // propagate vercel protection query parameters; map query parameters for design library request
206
+ const query = {};
207
+ req.nextUrl.searchParams.forEach((value, key) => {
208
+ query[key] = value;
209
+ });
210
+ const propagatedQsParams = Object.assign(Object.assign({}, getQueryParamsForPropagation(query)), mapEditingParams(query));
211
+ const base = resolveServerUrl(req);
212
+ const targetUrl = new URL('/', base);
213
+ for (const key in propagatedQsParams) {
214
+ if ({}.hasOwnProperty.call(propagatedQsParams, key)) {
215
+ propagatedQsParams[key] && targetUrl.searchParams.append(key, propagatedQsParams[key]);
216
+ }
217
+ }
218
+ targetUrl.searchParams.append('timestamp', Date.now().toString());
219
+ // enable draft mode in order to get prerender bypass cookie from request
220
+ const draft = yield draftMode();
221
+ draft.enable();
222
+ // add prerender bypass cookie to forwarded request in order to enable draft mode
223
+ const cookieStore = yield getNextCookies();
224
+ const reqCookie = req.headers.get('cookie') || '';
225
+ const prerenderBypassCookie = `${"__prerender_bypass" /* PreviewCookies.PRERENDER_BYPASS */}=${((_a = cookieStore.get("__prerender_bypass" /* PreviewCookies.PRERENDER_BYPASS */)) === null || _a === void 0 ? void 0 : _a.value) || ''}`;
226
+ const forwardCookie = reqCookie
227
+ ? `${reqCookie}; ${prerenderBypassCookie}`
228
+ : prerenderBypassCookie;
229
+ const forwardHeaders = new Headers(req.headers);
230
+ forwardHeaders.set('cookie', forwardCookie);
231
+ const forwardedResponse = yield dataFetcher.fetch(targetUrl.toString(), {
232
+ method: req.method,
233
+ headers: forwardHeaders,
234
+ body: req.body,
235
+ duplex: 'half',
236
+ });
237
+ // Filter out x-middleware headers since rewrites are not allowed in route handlers
238
+ // Also filter out content-encoding and content-length to avoid issues when browser reads the payload
239
+ const filteredHeaders = new Headers();
240
+ const forwardedHeaders = new Headers(forwardedResponse.headers);
241
+ forwardedHeaders.forEach((value, key) => {
242
+ if (key !== 'x-middleware-next' &&
243
+ key !== 'x-middleware-rewrite' &&
244
+ key !== 'content-encoding' &&
245
+ key !== 'content-length') {
246
+ filteredHeaders.set(key, value);
247
+ }
248
+ });
249
+ // Restrict the page to be rendered only within the allowed origins
250
+ filteredHeaders.set('Content-Security-Policy', getCSPHeader());
251
+ // add expected CORS headers to response
252
+ Object.entries(expectedCorsHeaders !== null && expectedCorsHeaders !== void 0 ? expectedCorsHeaders : {}).forEach(([key, value]) => {
253
+ filteredHeaders.set(key, value);
254
+ });
255
+ // remove nextjs preview cookies to not leak them to the browser
256
+ const filteredCookies = cleanupNextPreviewCookies(filteredHeaders.get('Set-Cookie'));
257
+ filteredHeaders.set('Set-Cookie', (filteredCookies === null || filteredCookies === void 0 ? void 0 : filteredCookies.join('; ')) || '');
258
+ return new Response(forwardedResponse.data, {
259
+ status: forwardedResponse.status,
260
+ statusText: forwardedResponse.statusText,
261
+ headers: filteredHeaders,
262
+ });
263
+ });
264
+ return { GET, POST, OPTIONS };
265
+ };
@@ -1,4 +1,4 @@
1
- export { createSitemapRouteHandler } from './sitemap-route-handler';
2
- export { createRobotsRouteHandler } from './robots-route-handler';
3
- export { createEditingConfigRouteHandler } from './editing-config-route-handler';
4
- export { createEditingRenderRouteHandlers } from './editing-render-route-handler';
1
+ export { createSitemapRouteHandler } from './sitemap-route-handler';
2
+ export { createRobotsRouteHandler } from './robots-route-handler';
3
+ export { createEditingConfigRouteHandler } from './editing-config-route-handler';
4
+ export { createEditingRenderRouteHandlers } from './editing-render-route-handler';
@@ -1,64 +1,65 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { SiteResolver } from '@sitecore-content-sdk/core/site';
11
- import { debug } from '@sitecore-content-sdk/core';
12
- import { unstable_cache } from 'next/cache';
13
- /**
14
- * Creates a route handler to serve the robots.txt file.
15
- * @param {RouteHandlerOptions} options - The options for the route handler.
16
- * @returns The route handler.
17
- */
18
- export const createRobotsRouteHandler = (options) => {
19
- const { client, sites, revalidate = 60 } = options;
20
- const siteResolver = new SiteResolver(sites);
21
- const getRobots = unstable_cache((site) => __awaiter(void 0, void 0, void 0, function* () {
22
- return client.getRobots(site);
23
- }), ['robots'], {
24
- revalidate,
25
- tags: ['robots'],
26
- });
27
- const GET = (req) => __awaiter(void 0, void 0, void 0, function* () {
28
- var _a;
29
- try {
30
- const startTimestamp = Date.now();
31
- const hostName = ((_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0]) || 'localhost';
32
- const site = siteResolver.getByHost(hostName);
33
- debug.robots('robots route handler start: %o', {
34
- hostName,
35
- siteName: site.name,
36
- });
37
- const robotsContent = yield getRobots(site.name);
38
- if (!robotsContent) {
39
- debug.robots('robots route handler end in %dms', Date.now() - startTimestamp);
40
- return new Response('User-agent: *\nDisallow: /', {
41
- status: 404,
42
- headers: {
43
- 'Content-Type': 'text/plain',
44
- },
45
- });
46
- }
47
- debug.robots('robots route handler end in %dms', Date.now() - startTimestamp);
48
- return new Response(robotsContent, {
49
- status: 200,
50
- headers: {
51
- 'Content-Type': 'text/plain',
52
- },
53
- });
54
- }
55
- catch (error) {
56
- console.log('Robots route handler failed:');
57
- console.log(error);
58
- return new Response('Internal Server Error', {
59
- status: 500,
60
- });
61
- }
62
- });
63
- return { GET };
64
- };
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { SiteResolver } from '@sitecore-content-sdk/core/site';
11
+ import { debug } from '@sitecore-content-sdk/core';
12
+ import { unstable_cache } from 'next/cache';
13
+ /**
14
+ * Creates a route handler to serve the robots.txt file.
15
+ * @param {RouteHandlerOptions} options - The options for the route handler.
16
+ * @returns The route handler object with GET method.
17
+ * @public
18
+ */
19
+ export const createRobotsRouteHandler = (options) => {
20
+ const { client, sites, revalidate = 60 } = options;
21
+ const siteResolver = new SiteResolver(sites);
22
+ const getRobots = unstable_cache((site) => __awaiter(void 0, void 0, void 0, function* () {
23
+ return client.getRobots(site);
24
+ }), ['robots'], {
25
+ revalidate,
26
+ tags: ['robots'],
27
+ });
28
+ const GET = (req) => __awaiter(void 0, void 0, void 0, function* () {
29
+ var _a;
30
+ try {
31
+ const startTimestamp = Date.now();
32
+ const hostName = ((_a = req.headers.get('host')) === null || _a === void 0 ? void 0 : _a.split(':')[0]) || 'localhost';
33
+ const site = siteResolver.getByHost(hostName);
34
+ debug.robots('robots route handler start: %o', {
35
+ hostName,
36
+ siteName: site.name,
37
+ });
38
+ const robotsContent = yield getRobots(site.name);
39
+ if (!robotsContent) {
40
+ debug.robots('robots route handler end in %dms', Date.now() - startTimestamp);
41
+ return new Response('User-agent: *\nDisallow: /', {
42
+ status: 404,
43
+ headers: {
44
+ 'Content-Type': 'text/plain',
45
+ },
46
+ });
47
+ }
48
+ debug.robots('robots route handler end in %dms', Date.now() - startTimestamp);
49
+ return new Response(robotsContent, {
50
+ status: 200,
51
+ headers: {
52
+ 'Content-Type': 'text/plain',
53
+ },
54
+ });
55
+ }
56
+ catch (error) {
57
+ console.log('Robots route handler failed:');
58
+ console.log(error);
59
+ return new Response('Internal Server Error', {
60
+ status: 500,
61
+ });
62
+ }
63
+ });
64
+ return { GET };
65
+ };