@akinon/next 2.0.28-beta.0 → 2.0.28-rc.0
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/CHANGELOG.md +25 -2
- package/bin/pz-generate-routes.js +4 -1
- package/components/plugin-module.tsx +0 -1
- package/data/client/checkout.ts +0 -1
- package/data/server/category.ts +13 -1
- package/data/server/list.ts +12 -0
- package/data/server/product.ts +10 -0
- package/data/server/special-page.ts +13 -0
- package/data/server/widget.ts +14 -1
- package/data/urls.ts +9 -4
- package/hooks/use-captcha.tsx +1 -1
- package/middlewares/default.ts +254 -249
- package/middlewares/masterpass-rest-callback.ts +89 -202
- package/package.json +2 -2
- package/plugins.d.ts +10 -0
- package/plugins.js +1 -0
- package/redux/middlewares/checkout.ts +45 -3
- package/redux/middlewares/pre-order/installment-option.ts +9 -1
- package/types/index.ts +20 -9
- package/utils/csrf.ts +1 -1
- package/utils/payload-optimizer.ts +481 -0
- package/with-pz-config.js +3 -2
|
@@ -7,224 +7,111 @@ import { getCheckoutPath } from '../utils';
|
|
|
7
7
|
|
|
8
8
|
const withMasterpassRestCallback =
|
|
9
9
|
(middleware: NextMiddleware) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const sessionId = req.cookies.get('osessionid');
|
|
14
|
-
|
|
15
|
-
if (!url.pathname.includes('/orders/masterpass-rest-callback')) {
|
|
16
|
-
return middleware(req, event);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (req.method !== 'POST') {
|
|
20
|
-
logger.warn('Invalid request method for masterpass REST callback', {
|
|
21
|
-
middleware: 'masterpass-rest-callback',
|
|
22
|
-
method: req.method,
|
|
23
|
-
ip
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
return NextResponse.redirect(
|
|
27
|
-
`${url.origin}${getUrlPathWithLocale(
|
|
28
|
-
'/orders/checkout/',
|
|
29
|
-
req.cookies.get('pz-locale')?.value
|
|
30
|
-
)}`,
|
|
31
|
-
303
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const responseCode = url.searchParams.get('responseCode');
|
|
36
|
-
const token = url.searchParams.get('token');
|
|
37
|
-
|
|
38
|
-
if (!responseCode || !token) {
|
|
39
|
-
logger.warn('Missing required parameters for masterpass REST callback', {
|
|
40
|
-
middleware: 'masterpass-rest-callback',
|
|
41
|
-
responseCode,
|
|
42
|
-
token,
|
|
43
|
-
ip
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return NextResponse.redirect(
|
|
47
|
-
`${url.origin}${getUrlPathWithLocale(
|
|
48
|
-
'/orders/checkout/',
|
|
49
|
-
req.cookies.get('pz-locale')?.value
|
|
50
|
-
)}`,
|
|
51
|
-
303
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const formData = await req.formData();
|
|
57
|
-
const body: Record<string, string> = {};
|
|
58
|
-
|
|
59
|
-
Array.from(formData.entries()).forEach(([key, value]) => {
|
|
60
|
-
body[key] = value.toString();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (!sessionId) {
|
|
64
|
-
logger.warn(
|
|
65
|
-
'Make sure that the SESSION_COOKIE_SAMESITE environment variable is set to None in Commerce.',
|
|
66
|
-
{
|
|
67
|
-
middleware: 'masterpass-rest-callback',
|
|
68
|
-
ip
|
|
69
|
-
}
|
|
70
|
-
);
|
|
10
|
+
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
11
|
+
const url = req.nextUrl.clone();
|
|
12
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
71
13
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
req.cookies.get('pz-locale')?.value
|
|
76
|
-
)}`,
|
|
77
|
-
303
|
|
78
|
-
);
|
|
79
|
-
}
|
|
14
|
+
const isMasterpassCompletePage =
|
|
15
|
+
url.pathname.includes('/orders/checkout') &&
|
|
16
|
+
url.searchParams.get('page') === 'MasterpassRestCompletePage';
|
|
80
17
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
requestUrl.searchParams.set('page', 'MasterpassRestCompletePage');
|
|
84
|
-
requestUrl.searchParams.set('responseCode', responseCode);
|
|
85
|
-
requestUrl.searchParams.set('token', token);
|
|
86
|
-
requestUrl.searchParams.set(
|
|
87
|
-
'three_d_secure',
|
|
88
|
-
body.transactionType?.includes('3D') ? 'true' : 'false'
|
|
89
|
-
);
|
|
90
|
-
requestUrl.searchParams.set(
|
|
91
|
-
'transactionType',
|
|
92
|
-
body.transactionType || ''
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const requestHeaders = {
|
|
96
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
97
|
-
'X-Requested-With': 'XMLHttpRequest',
|
|
98
|
-
Cookie: req.headers.get('cookie') ?? '',
|
|
99
|
-
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
100
|
-
'x-forwarded-for': ip,
|
|
101
|
-
'User-Agent': req.headers.get('user-agent') ?? ''
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const request = await fetch(requestUrl.toString(), {
|
|
105
|
-
method: 'POST',
|
|
106
|
-
headers: requestHeaders,
|
|
107
|
-
body: new URLSearchParams(body)
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
logger.info('Masterpass REST callback request', {
|
|
111
|
-
requestUrl: requestUrl.toString(),
|
|
112
|
-
status: request.status,
|
|
113
|
-
requestHeaders,
|
|
114
|
-
ip
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const response = await request.json();
|
|
118
|
-
|
|
119
|
-
const { context_list: contextList, errors } = response;
|
|
120
|
-
|
|
121
|
-
let redirectUrl = response.redirect_url;
|
|
122
|
-
|
|
123
|
-
if (!redirectUrl && contextList && contextList.length > 0) {
|
|
124
|
-
for (const context of contextList) {
|
|
125
|
-
if (context.page_context && context.page_context.redirect_url) {
|
|
126
|
-
redirectUrl = context.page_context.redirect_url;
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
18
|
+
if (!isMasterpassCompletePage) {
|
|
19
|
+
return middleware(req, event);
|
|
130
20
|
}
|
|
131
21
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
22
|
+
try {
|
|
23
|
+
const isPostCheckout = req.cookies.get('pz-post-checkout-flow')?.value === 'true';
|
|
24
|
+
const requestUrl = new URL(getCheckoutPath(isPostCheckout), Settings.commerceUrl);
|
|
25
|
+
|
|
26
|
+
url.searchParams.forEach((value, key) => {
|
|
27
|
+
requestUrl.searchParams.set(key, value);
|
|
138
28
|
});
|
|
139
29
|
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
'/orders/checkout/',
|
|
143
|
-
req.cookies.get('pz-locale')?.value
|
|
144
|
-
)}`,
|
|
145
|
-
{
|
|
146
|
-
status: 303,
|
|
147
|
-
headers: {
|
|
148
|
-
'Set-Cookie': `pz-pos-error=${encodeURIComponent(JSON.stringify(errors))}; path=/;`
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
);
|
|
30
|
+
const formData = await req.formData();
|
|
31
|
+
const body: Record<string, string> = {};
|
|
152
32
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
path: '/'
|
|
33
|
+
Array.from(formData.entries()).forEach(([key, value]) => {
|
|
34
|
+
body[key] = value.toString();
|
|
156
35
|
});
|
|
157
36
|
|
|
158
|
-
|
|
159
|
-
|
|
37
|
+
const requestHeaders = {
|
|
38
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
39
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
40
|
+
Cookie: req.headers.get('cookie') ?? '',
|
|
41
|
+
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
42
|
+
'x-forwarded-for': ip,
|
|
43
|
+
'User-Agent': req.headers.get('user-agent') ?? ''
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const request = await fetch(requestUrl.toString(), {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: requestHeaders,
|
|
49
|
+
body: new URLSearchParams(body)
|
|
50
|
+
});
|
|
160
51
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
if (!redirectUrl) {
|
|
169
|
-
logger.warn(
|
|
170
|
-
'No redirection url found in response. Redirecting to checkout page.',
|
|
171
|
-
{
|
|
52
|
+
const response = await request.json();
|
|
53
|
+
const { errors } = response;
|
|
54
|
+
|
|
55
|
+
if (errors && Object.keys(errors).length) {
|
|
56
|
+
logger.error('Error while processing MasterpassRestCompletePage', {
|
|
172
57
|
middleware: 'masterpass-rest-callback',
|
|
173
|
-
|
|
174
|
-
response: JSON.stringify(response),
|
|
58
|
+
errors,
|
|
175
59
|
ip
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const errorResponse = NextResponse.redirect(
|
|
63
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
64
|
+
'/orders/checkout/',
|
|
65
|
+
req.cookies.get('pz-locale')?.value
|
|
66
|
+
)}`,
|
|
67
|
+
303
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Add error cookie
|
|
71
|
+
errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
|
|
72
|
+
path: '/'
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return errorResponse;
|
|
76
|
+
}
|
|
191
77
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
78
|
+
const redirectUrl =
|
|
79
|
+
response.redirect_url ||
|
|
80
|
+
response.context_list?.[0]?.page_context?.redirect_url;
|
|
81
|
+
|
|
82
|
+
if (redirectUrl) {
|
|
83
|
+
const nextResponse = NextResponse.redirect(
|
|
84
|
+
`${url.origin}${getUrlPathWithLocale(redirectUrl, req.cookies.get('pz-locale')?.value)}`,
|
|
85
|
+
303
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Forward set-cookie headers from the upstream response
|
|
89
|
+
const setCookieHeader = request.headers.get('set-cookie');
|
|
90
|
+
if (setCookieHeader) {
|
|
91
|
+
setCookieHeader.split(',').forEach((cookie) => {
|
|
92
|
+
nextResponse.headers.append('Set-Cookie', cookie.trim());
|
|
93
|
+
});
|
|
94
|
+
}
|
|
197
95
|
|
|
198
|
-
|
|
96
|
+
return nextResponse;
|
|
97
|
+
}
|
|
199
98
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
99
|
+
return NextResponse.redirect(
|
|
100
|
+
`${url.origin}${getUrlPathWithLocale('/orders/checkout/', req.cookies.get('pz-locale')?.value)}`,
|
|
101
|
+
303
|
|
102
|
+
);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
logger.error('Error while processing MasterpassRestCompletePage', {
|
|
105
|
+
middleware: 'masterpass-rest-callback',
|
|
106
|
+
error,
|
|
107
|
+
ip
|
|
205
108
|
});
|
|
206
|
-
}
|
|
207
109
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
Cookie: req.headers.get('cookie') ?? '',
|
|
215
|
-
'x-currency': req.cookies.get('pz-currency')?.value ?? ''
|
|
216
|
-
},
|
|
217
|
-
ip
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
return NextResponse.redirect(
|
|
221
|
-
`${url.origin}${getUrlPathWithLocale(
|
|
222
|
-
'/orders/checkout/',
|
|
223
|
-
req.cookies.get('pz-locale')?.value
|
|
224
|
-
)}`,
|
|
225
|
-
303
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
};
|
|
110
|
+
return NextResponse.redirect(
|
|
111
|
+
`${url.origin}${getUrlPathWithLocale('/orders/checkout/', req.cookies.get('pz-locale')?.value)}`,
|
|
112
|
+
303
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
229
116
|
|
|
230
117
|
export default withMasterpassRestCallback;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/next",
|
|
3
3
|
"description": "Core package for Project Zero Next",
|
|
4
|
-
"version": "2.0.28-
|
|
4
|
+
"version": "2.0.28-rc.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"set-cookie-parser": "2.6.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@akinon/eslint-plugin-projectzero": "2.0.28-
|
|
39
|
+
"@akinon/eslint-plugin-projectzero": "2.0.28-rc.0",
|
|
40
40
|
"@babel/core": "7.26.10",
|
|
41
41
|
"@babel/preset-env": "7.26.9",
|
|
42
42
|
"@babel/preset-typescript": "7.27.0",
|
package/plugins.d.ts
CHANGED
|
@@ -37,6 +37,16 @@ declare module '@akinon/pz-cybersource-uc/src/redux/middleware' {
|
|
|
37
37
|
export default middleware as any;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
declare module '@akinon/pz-apple-pay' {}
|
|
41
|
+
|
|
42
|
+
declare module '@akinon/pz-similar-products' {
|
|
43
|
+
export const SimilarProductsModal: any;
|
|
44
|
+
export const SimilarProductsFilterSidebar: any;
|
|
45
|
+
export const SimilarProductsResultsGrid: any;
|
|
46
|
+
export const SimilarProductsPlugin: any;
|
|
47
|
+
export const SimilarProductsButtonPlugin: any;
|
|
48
|
+
}
|
|
49
|
+
|
|
40
50
|
declare module '@akinon/pz-cybersource-uc/src/redux/reducer' {
|
|
41
51
|
export default reducer as any;
|
|
42
52
|
}
|
package/plugins.js
CHANGED
|
@@ -26,13 +26,28 @@ import {
|
|
|
26
26
|
} from '../../redux/reducers/checkout';
|
|
27
27
|
import { RootState, TypedDispatch } from 'redux/store';
|
|
28
28
|
import { checkoutApi } from '../../data/client/checkout';
|
|
29
|
-
import { CheckoutContext, PreOrder } from '../../types';
|
|
29
|
+
import { CheckoutContext, MiddlewareAction, PreOrder } from '../../types';
|
|
30
30
|
import { getCookie } from '../../utils';
|
|
31
31
|
import settings from 'settings';
|
|
32
32
|
import { LocaleUrlStrategy } from '../../localization';
|
|
33
33
|
import { showMobile3dIframe } from '../../utils/mobile-3d-iframe';
|
|
34
34
|
import { showRedirectionIframe } from '../../utils/redirection-iframe';
|
|
35
35
|
|
|
36
|
+
const IFRAME_REDIRECTION_KEY = 'pz-iframe-redirection-active';
|
|
37
|
+
|
|
38
|
+
const isIframeRedirectionActive = () =>
|
|
39
|
+
typeof window !== 'undefined' &&
|
|
40
|
+
sessionStorage.getItem(IFRAME_REDIRECTION_KEY) === 'true';
|
|
41
|
+
|
|
42
|
+
const setIframeRedirectionActive = (active: boolean) => {
|
|
43
|
+
if (typeof window === 'undefined') return;
|
|
44
|
+
if (active) {
|
|
45
|
+
sessionStorage.setItem(IFRAME_REDIRECTION_KEY, 'true');
|
|
46
|
+
} else {
|
|
47
|
+
sessionStorage.removeItem(IFRAME_REDIRECTION_KEY);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
36
51
|
interface CheckoutResult {
|
|
37
52
|
payload: {
|
|
38
53
|
errors?: Record<string, string[]>;
|
|
@@ -69,7 +84,7 @@ export const redirectUrlMiddleware: Middleware = () => {
|
|
|
69
84
|
const result = next(action) as CheckoutResult;
|
|
70
85
|
const redirectUrl = result?.payload?.redirect_url;
|
|
71
86
|
|
|
72
|
-
if (redirectUrl) {
|
|
87
|
+
if (redirectUrl && !isIframeRedirectionActive()) {
|
|
73
88
|
const currentLocale = getCookie('pz-locale');
|
|
74
89
|
|
|
75
90
|
let url = redirectUrl;
|
|
@@ -99,8 +114,15 @@ export const contextListMiddleware: Middleware = ({
|
|
|
99
114
|
const { isMobileApp, userPhoneNumber } = getState().root;
|
|
100
115
|
const result = next(action) as CheckoutResult;
|
|
101
116
|
const preOrder = result?.payload?.pre_order;
|
|
117
|
+
const act = action as MiddlewareAction;
|
|
102
118
|
|
|
103
119
|
if (result?.payload?.context_list) {
|
|
120
|
+
const endpointName = act.meta?.arg?.endpointName;
|
|
121
|
+
const isBinNumberResponse = endpointName === 'setBinNumber';
|
|
122
|
+
const hasCardTypeInContextList = result.payload.context_list.some(
|
|
123
|
+
(ctx) => ctx.page_context.card_type
|
|
124
|
+
);
|
|
125
|
+
|
|
104
126
|
result.payload.context_list.forEach((context) => {
|
|
105
127
|
const redirectUrl = context.page_context.redirect_url;
|
|
106
128
|
const isIframe = context.page_context.is_iframe ?? false;
|
|
@@ -134,6 +156,7 @@ export const contextListMiddleware: Middleware = ({
|
|
|
134
156
|
if (isMobileDevice && isIframePaymentOptionIncluded) {
|
|
135
157
|
showMobile3dIframe(urlObj.toString());
|
|
136
158
|
} else if (isIframe) {
|
|
159
|
+
setIframeRedirectionActive(true);
|
|
137
160
|
showRedirectionIframe(urlObj.toString());
|
|
138
161
|
} else {
|
|
139
162
|
window.location.href = urlObj.toString();
|
|
@@ -209,15 +232,34 @@ export const contextListMiddleware: Middleware = ({
|
|
|
209
232
|
(ctx) => ctx.page_name === 'DeliveryOptionSelectionPage'
|
|
210
233
|
)
|
|
211
234
|
) {
|
|
235
|
+
const isCreditCardPayment =
|
|
236
|
+
preOrder?.payment_option?.payment_type === 'credit_card' ||
|
|
237
|
+
preOrder?.payment_option?.payment_type === 'masterpass';
|
|
238
|
+
|
|
212
239
|
if (context.page_context.card_type) {
|
|
213
240
|
dispatch(setCardType(context.page_context.card_type));
|
|
241
|
+
} else if (
|
|
242
|
+
isCreditCardPayment &&
|
|
243
|
+
isBinNumberResponse &&
|
|
244
|
+
!hasCardTypeInContextList
|
|
245
|
+
) {
|
|
246
|
+
dispatch(setCardType(null));
|
|
247
|
+
dispatch(setInstallmentOptions([]));
|
|
214
248
|
}
|
|
215
249
|
|
|
216
250
|
if (
|
|
217
251
|
context.page_context.installments &&
|
|
218
252
|
preOrder?.payment_option?.payment_type !== 'masterpass_rest'
|
|
219
253
|
) {
|
|
220
|
-
|
|
254
|
+
if (
|
|
255
|
+
!isCreditCardPayment ||
|
|
256
|
+
context.page_context.card_type ||
|
|
257
|
+
hasCardTypeInContextList
|
|
258
|
+
) {
|
|
259
|
+
dispatch(
|
|
260
|
+
setInstallmentOptions(context.page_context.installments)
|
|
261
|
+
);
|
|
262
|
+
}
|
|
221
263
|
}
|
|
222
264
|
}
|
|
223
265
|
|
|
@@ -14,9 +14,17 @@ export const installmentOptionMiddleware: Middleware = ({
|
|
|
14
14
|
return result;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const { installmentOptions } = getState().checkout;
|
|
17
|
+
const { installmentOptions, cardType } = getState().checkout;
|
|
18
18
|
const { endpoints: apiEndpoints } = checkoutApi;
|
|
19
19
|
|
|
20
|
+
const isCreditCardPayment =
|
|
21
|
+
preOrder?.payment_option?.payment_type === 'credit_card' ||
|
|
22
|
+
preOrder?.payment_option?.payment_type === 'masterpass';
|
|
23
|
+
|
|
24
|
+
if (isCreditCardPayment && !cardType) {
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
if (
|
|
21
29
|
!preOrder?.installment &&
|
|
22
30
|
preOrder?.payment_option?.payment_type !== 'saved_card' &&
|
package/types/index.ts
CHANGED
|
@@ -85,6 +85,12 @@ export interface Settings {
|
|
|
85
85
|
};
|
|
86
86
|
usePrettyUrlRoute?: boolean;
|
|
87
87
|
commerceUrl: string;
|
|
88
|
+
/**
|
|
89
|
+
* This option allows you to track Sentry events on the client side, in addition to server and edge environments.
|
|
90
|
+
*
|
|
91
|
+
* It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
|
|
92
|
+
*/
|
|
93
|
+
sentryDsn?: string;
|
|
88
94
|
/**
|
|
89
95
|
* CSRF cookie hardening settings.
|
|
90
96
|
*
|
|
@@ -236,6 +242,7 @@ export interface Settings {
|
|
|
236
242
|
separator?: string;
|
|
237
243
|
segments: PzSegmentDefinition[];
|
|
238
244
|
};
|
|
245
|
+
payloadOptimization?: import('../utils/payload-optimizer').PayloadOptimizationConfig;
|
|
239
246
|
}
|
|
240
247
|
|
|
241
248
|
export interface CacheOptions {
|
|
@@ -295,7 +302,9 @@ export interface PzSegmentsConfig {
|
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
// Search params type compatible with both Next.js resolved searchParams and URLSearchParams
|
|
298
|
-
export type SearchParams =
|
|
305
|
+
export type SearchParams =
|
|
306
|
+
| Record<string, string | string[] | undefined>
|
|
307
|
+
| URLSearchParams;
|
|
299
308
|
|
|
300
309
|
// Raw Next 16 server prop shape, used at the middleware/HOC boundary before normalization
|
|
301
310
|
export type RawSearchParams = Record<string, string | string[] | undefined>;
|
|
@@ -328,14 +337,16 @@ export interface RootLayoutProps<T = any> extends LayoutProps<T> {
|
|
|
328
337
|
|
|
329
338
|
// Async versions for Next.js 16 generateMetadata and internal use
|
|
330
339
|
export interface AsyncPageProps<T = any> {
|
|
331
|
-
params: Promise<
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
340
|
+
params: Promise<
|
|
341
|
+
T & {
|
|
342
|
+
pz?: string;
|
|
343
|
+
commerce?: string;
|
|
344
|
+
locale?: string;
|
|
345
|
+
currency?: string;
|
|
346
|
+
url?: string;
|
|
347
|
+
[key: string]: any;
|
|
348
|
+
}
|
|
349
|
+
>;
|
|
339
350
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
|
340
351
|
}
|
|
341
352
|
|
package/utils/csrf.ts
CHANGED
|
@@ -31,7 +31,7 @@ export function getCsrfCookieFlags(): CsrfCookieFlags {
|
|
|
31
31
|
const httpOnly = isCsrfHttpOnly();
|
|
32
32
|
return {
|
|
33
33
|
httpOnly,
|
|
34
|
-
secure:
|
|
34
|
+
secure: process.env.NODE_ENV === 'production',
|
|
35
35
|
sameSite: 'lax'
|
|
36
36
|
};
|
|
37
37
|
}
|