@akinon/next 2.0.0-beta.13 → 2.0.0-beta.15

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 2.0.0-beta.15
4
+
5
+ ### Minor Changes
6
+
7
+ - 49c82e1a: ZERO-4047: Remove Sentry configuration from default Next.js config
8
+ - d7e5178b: ZERO-3985: Add query string handling for orders redirection in middleware
9
+ - b59fdd1c: ZERO-4009: Add password reset token validation
10
+
11
+ ## 2.0.0-beta.14
12
+
13
+ ### Minor Changes
14
+
15
+ - aef81c5d: ZERO-4034: Refactor checkout API to use dynamic store imports for improved performance
16
+ - 0754c835: ZERO-4063: Add support for optional Redis password in cache handlers
17
+ - c6c5c1cd: ZERO-4128: Use cookies API for pz-pos-error to ensure delivery on 303 redirects
18
+
3
19
  ## 2.0.0-beta.13
4
20
 
5
21
  ### Minor Changes
@@ -77,6 +77,10 @@ interface LoyaltyTransactions {
77
77
  }[];
78
78
  }
79
79
 
80
+ interface PasswordResetValidateResponse {
81
+ validlink: boolean;
82
+ }
83
+
80
84
  const accountApi = api.injectEndpoints({
81
85
  endpoints: (builder) => ({
82
86
  updatePassword: builder.mutation<void, AccountChangePasswordFormType>({
@@ -221,6 +225,12 @@ const accountApi = api.injectEndpoints({
221
225
  }),
222
226
  getLoyaltyTransactions: builder.query<LoyaltyTransactions, void>({
223
227
  query: () => buildClientRequestUrl(account.loyaltyTransactions)
228
+ }),
229
+ getValidatePasswordResetToken: builder.query<
230
+ PasswordResetValidateResponse,
231
+ string
232
+ >({
233
+ query: (slug) => buildClientRequestUrl(account.passwordReset(slug))
224
234
  })
225
235
  }),
226
236
  overrideExisting: true
@@ -247,5 +257,6 @@ export const {
247
257
  usePasswordResetMutation,
248
258
  useAnonymizeMutation,
249
259
  useGetLoyaltyBalanceQuery,
250
- useGetLoyaltyTransactionsQuery
260
+ useGetLoyaltyTransactionsQuery,
261
+ useGetValidatePasswordResetTokenQuery
251
262
  } = accountApi;
@@ -364,11 +364,17 @@ CacheHandler.onCreation(async () => {
364
364
  };
365
365
  }
366
366
 
367
- const redisHandler = createRedisHandler({
367
+ const redisOptions = {
368
368
  client,
369
369
  timeoutMs: CACHE_CONFIG.redis.timeoutMs,
370
370
  keyExpirationStrategy: 'EXPIREAT'
371
- });
371
+ };
372
+
373
+ if (process.env.CACHE_PASSWORD) {
374
+ redisOptions.password = process.env.CACHE_PASSWORD;
375
+ }
376
+
377
+ const redisHandler = createRedisHandler(redisOptions);
372
378
 
373
379
  const localHandler = createLruHandler(CACHE_CONFIG.lru);
374
380
 
package/lib/cache.ts CHANGED
@@ -155,9 +155,14 @@ export class Cache {
155
155
  process.env.CACHE_PORT
156
156
  }/${process.env.CACHE_BUCKET ?? '0'}`;
157
157
 
158
- const client: RedisClientType = createClient({
159
- url: redisUrl
160
- });
158
+ const options = {
159
+ url: redisUrl,
160
+ ...(process.env.CACHE_PASSWORD && {
161
+ password: process.env.CACHE_PASSWORD
162
+ })
163
+ };
164
+
165
+ const client: RedisClientType = createClient(options);
161
166
 
162
167
  client.on('error', (error) => {
163
168
  logger.error('Redis client error', { redisUrl, error });
@@ -110,10 +110,9 @@ const withCompleteGpay =
110
110
  });
111
111
 
112
112
  // Add error cookie
113
- errorResponse.headers.append(
114
- 'Set-Cookie',
115
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
116
- );
113
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
114
+ path: '/'
115
+ });
117
116
 
118
117
  return errorResponse;
119
118
  }
@@ -111,10 +111,9 @@ const withCompleteMasterpass =
111
111
  });
112
112
 
113
113
  // Add error cookie
114
- errorResponse.headers.append(
115
- 'Set-Cookie',
116
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
117
- );
114
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
115
+ path: '/'
116
+ });
118
117
 
119
118
  return errorResponse;
120
119
  }
@@ -107,10 +107,9 @@ const withCompleteWallet =
107
107
  });
108
108
 
109
109
  // Add error cookie
110
- errorResponse.headers.append(
111
- 'Set-Cookie',
112
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
113
- );
110
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
111
+ path: '/'
112
+ });
114
113
 
115
114
  return errorResponse;
116
115
  }
@@ -132,8 +132,13 @@ const withPzDefault =
132
132
  }
133
133
 
134
134
  if (req.nextUrl.pathname.startsWith('/orders/redirection/')) {
135
+ const queryString = searchParams.toString();
135
136
  return NextResponse.rewrite(
136
- new URL(`${encodeURI(Settings.commerceUrl)}/orders/redirection/`)
137
+ new URL(
138
+ `${encodeURI(Settings.commerceUrl)}/orders/redirection/${
139
+ queryString ? `?${queryString}` : ''
140
+ }`
141
+ )
137
142
  );
138
143
  }
139
144
 
@@ -137,7 +137,7 @@ const withMasterpassRestCallback =
137
137
  ip
138
138
  });
139
139
 
140
- return NextResponse.redirect(
140
+ const errorResponse = NextResponse.redirect(
141
141
  `${url.origin}${getUrlPathWithLocale(
142
142
  '/orders/checkout/',
143
143
  req.cookies.get('pz-locale')?.value
@@ -145,10 +145,17 @@ const withMasterpassRestCallback =
145
145
  {
146
146
  status: 303,
147
147
  headers: {
148
- 'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
148
+ 'Set-Cookie': `pz-pos-error=${encodeURIComponent(JSON.stringify(errors))}; path=/;`
149
149
  }
150
150
  }
151
151
  );
152
+
153
+ // Add error cookie
154
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
155
+ path: '/'
156
+ });
157
+
158
+ return errorResponse;
152
159
  }
153
160
 
154
161
  logger.info('Masterpass REST callback response', {
@@ -184,16 +191,19 @@ const withMasterpassRestCallback =
184
191
 
185
192
  logger.info('Redirecting after masterpass REST callback', {
186
193
  middleware: 'masterpass-rest-callback',
187
- redirectUrlWithLocale,
194
+ redirectUrl: redirectUrlWithLocale,
188
195
  ip
189
196
  });
190
197
 
191
198
  const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
192
199
 
193
- nextResponse.headers.set(
194
- 'Set-Cookie',
195
- request.headers.get('set-cookie') ?? ''
196
- );
200
+ // Forward set-cookie headers from the upstream response
201
+ const setCookieHeader = request.headers.get('set-cookie');
202
+ if (setCookieHeader) {
203
+ setCookieHeader.split(',').forEach((cookie) => {
204
+ nextResponse.headers.append('Set-Cookie', cookie.trim());
205
+ });
206
+ }
197
207
 
198
208
  return nextResponse;
199
209
  } catch (error) {
@@ -111,10 +111,9 @@ const withRedirectionPayment =
111
111
  });
112
112
 
113
113
  // Add error cookie
114
- errorResponse.headers.append(
115
- 'Set-Cookie',
116
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
117
- );
114
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
115
+ path: '/'
116
+ });
118
117
 
119
118
  return errorResponse;
120
119
  }
@@ -111,10 +111,9 @@ const withSavedCardRedirection =
111
111
  });
112
112
 
113
113
  // Add error cookie
114
- errorResponse.headers.append(
115
- 'Set-Cookie',
116
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
117
- );
114
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
115
+ path: '/'
116
+ });
118
117
 
119
118
  return errorResponse;
120
119
  }
@@ -110,10 +110,9 @@ const withThreeDRedirection =
110
110
  });
111
111
 
112
112
  // Add error cookie
113
- errorResponse.headers.append(
114
- 'Set-Cookie',
115
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
116
- );
113
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
114
+ path: '/'
115
+ });
117
116
 
118
117
  return errorResponse;
119
118
  }
@@ -131,10 +131,9 @@ const withWalletCompleteRedirection =
131
131
  });
132
132
 
133
133
  // Add error cookie
134
- errorResponse.headers.append(
135
- 'Set-Cookie',
136
- `pz-pos-error=${JSON.stringify(errors)}; path=/;`
137
- );
134
+ errorResponse.cookies.set('pz-pos-error', JSON.stringify(errors), {
135
+ path: '/'
136
+ });
138
137
 
139
138
  return errorResponse;
140
139
  }
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.0-beta.13",
4
+ "version": "2.0.0-beta.15",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "set-cookie-parser": "2.6.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@akinon/eslint-plugin-projectzero": "2.0.0-beta.13",
38
+ "@akinon/eslint-plugin-projectzero": "2.0.0-beta.15",
39
39
  "@babel/core": "7.26.10",
40
40
  "@babel/preset-env": "7.26.9",
41
41
  "@babel/preset-typescript": "7.27.0",
package/utils/index.ts CHANGED
@@ -196,7 +196,13 @@ export const urlLocaleMatcherRegex = new RegExp(
196
196
 
197
197
  export const getPosError = () => {
198
198
  const cookieValue = getCookie('pz-pos-error');
199
- const error = JSON.parse(cookieValue ? decodeURIComponent(cookieValue) : '{}');
199
+ let decoded: string;
200
+ try {
201
+ decoded = cookieValue ? decodeURIComponent(cookieValue) : '{}';
202
+ } catch {
203
+ decoded = cookieValue ?? '{}';
204
+ }
205
+ const error = JSON.parse(decoded);
200
206
 
201
207
  // delete 'pz-pos-error' cookie when refreshing or closing page
202
208
  window.addEventListener('beforeunload', () => {
@@ -206,6 +212,23 @@ export const getPosError = () => {
206
212
  return error;
207
213
  };
208
214
 
215
+ export const checkPaymentWillRedirect = (response: {
216
+ context_list?: Array<{
217
+ page_name: string;
218
+ page_context?: { context_data?: { redirect_url?: string } };
219
+ }>;
220
+ redirect_url?: string;
221
+ errors?: unknown;
222
+ }): boolean => {
223
+ if (!response) return false;
224
+
225
+ const hasThankYouPage = response.context_list?.some(
226
+ (c) => c.page_name === 'ThankYouPage'
227
+ );
228
+
229
+ return Boolean(hasThankYouPage || response.redirect_url);
230
+ };
231
+
209
232
  export const urlSchemes = [
210
233
  'http',
211
234
  'tel:',
package/with-pz-config.js CHANGED
@@ -71,7 +71,7 @@ const defaultConfig = {
71
71
  translations: false
72
72
  };
73
73
  return config;
74
- },
74
+ }
75
75
  };
76
76
 
77
77
  const withPzConfig = (