@akinon/next 1.21.0-rc.9 → 1.21.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 CHANGED
@@ -1,71 +1,18 @@
1
1
  # @akinon/next
2
2
 
3
- ## 1.21.0-rc.9
4
-
5
- ### Minor Changes
6
-
7
- - 8d6caba: ZERO-2434: enhance error handling and logging in appFetch function
8
-
9
- ## 1.21.0-rc.8
10
-
11
- ### Minor Changes
12
-
13
- - 07cc81a: Add infinite and more types to pagination
14
-
15
- ## 1.21.0-rc.7
16
-
17
- ### Minor Changes
18
-
19
- - 5ace3508: ZERO-2439: Add anonymous tracking page
20
- - be04d041: ZERO-2452: UA events converted to be compatible with GA4 and types are declared
21
- - c75e1e45: ZERO-2452: GA4 support for gtm events
22
-
23
- ## 1.21.0-rc.6
24
-
25
- ### Minor Changes
26
-
27
- - b4452e9d: ZERO-2463: Refactor Sentry initialization and add Sentry DSN option to settings
28
-
29
- ## 1.21.0-rc.5
30
-
31
- ### Patch Changes
32
-
33
- - ZERO-2296: Fix ROUTES import
34
-
35
- ## 1.21.0-rc.4
36
-
37
- ### Minor Changes
38
-
39
- - Revert ZERO-2435
40
-
41
- ## 1.21.0-rc.3
42
-
43
- ### Minor Changes
44
-
45
- - af8e38e0: ZERO-2247: Add additionalParams to MasterpassProvider and set them in buildPurchaseForm and buildDirectPurchaseForm
46
- - 16027410: ZERO-2451: Refactor extraHeaders assignment in client.ts
47
- - 9edd725b: Datalayer init changed to 3rd party script. Declare is the same as next
48
-
49
- ## 1.21.0-rc.2
50
-
51
- ### Minor Changes
52
-
53
- - 8075006: install plugins check the akinon version
54
- - 32668ed: ZERO-2296: Implement Checkout Provider Middleware and Enhancements
55
- - 29191da: ImageLoader supports crop none
56
-
57
- ## 1.21.0-rc.1
58
-
59
- ### Minor Changes
60
-
61
- - e910b228: ZERO-2421: Upgrade next version to 14.1.0
62
- - 1b4b0fa1: Redis connection change to connection pool
63
-
64
- ## 1.21.0-rc.0
3
+ ## 1.21.0
65
4
 
66
5
  ### Minor Changes
67
6
 
7
+ - 5ace350: ZERO-2439: Add anonymous tracking page
8
+ - be04d04: ZERO-2452: UA events converted to be compatible with GA4 and types are declared
9
+ - e910b22: ZERO-2421: Upgrade next version to 14.1.0
10
+ - af8e38e: ZERO-2247: Add additionalParams to MasterpassProvider and set them in buildPurchaseForm and buildDirectPurchaseForm
68
11
  - 26a74c9: ZERO-2436: Add getCoupons and setCoupon API endpoints
12
+ - 1602741: ZERO-2451: Refactor extraHeaders assignment in client.ts
13
+ - 9edd725: Datalayer init changed to 3rd party script. Declare is the same as next
14
+ - c75e1e4: ZERO-2452: GA4 support for gtm events
15
+ - 29191da: ImageLoader supports crop none
69
16
 
70
17
  ## 1.20.0
71
18
 
package/api/auth.ts CHANGED
@@ -220,17 +220,6 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
220
220
  pages: {
221
221
  signIn: ROUTES.AUTH,
222
222
  error: ROUTES.AUTH
223
- },
224
- cookies: {
225
- sessionToken: {
226
- name: `__Secure-next-auth.session-token`,
227
- options: {
228
- httpOnly: true,
229
- sameSite: 'none',
230
- path: '/',
231
- secure: true
232
- }
233
- }
234
223
  }
235
224
  };
236
225
  };
@@ -1,71 +1,39 @@
1
+ #!/usr/bin/env node
2
+
1
3
  const fs = require('fs');
2
4
  const path = require('path');
3
- const { execSync } = require('child_process');
4
-
5
- function findBaseDir() {
6
- const insideNodeModules = __dirname.includes('node_modules');
7
- return insideNodeModules
8
- ? process.cwd()
9
- : path.resolve(__dirname, '../../../apps/projectzeronext');
10
- }
5
+ const rootDir = path.resolve(process.cwd());
6
+ const spawn = require('cross-spawn');
7
+ const availablePlugins = require('../plugins');
11
8
 
12
- const BASE_DIR = findBaseDir();
13
- const getFullPath = (relativePath) => path.join(BASE_DIR, relativePath);
14
-
15
- const packageJsonPath = getFullPath('package.json');
16
- let packageJson;
9
+ let plugins;
17
10
 
18
11
  try {
19
- packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
12
+ plugins = require(path.resolve(rootDir, './src/plugins.js'));
20
13
  } catch (error) {
21
- console.error('Error reading package.json:', error);
22
- process.exit(1);
14
+ console.error('No plugins.js file found, skipping plugin installation.');
15
+ process.exit(0);
23
16
  }
24
17
 
25
- const pluginsJsPath = getFullPath('src/plugins.js');
26
- let installedPlugins;
27
-
28
- try {
29
- installedPlugins = require(pluginsJsPath);
30
- } catch (error) {
31
- console.error('Error loading installed plugins:', error);
32
- process.exit(1);
33
- }
18
+ let installCmd = [];
34
19
 
35
- const protectedPackages = ['@akinon/next', 'next'];
20
+ availablePlugins
21
+ .filter((p) => plugins?.includes(p))
22
+ .forEach((name) => {
23
+ installCmd.push(`@akinon/${name}`);
24
+ });
36
25
 
37
- const pluginsToRemove = Object.keys(packageJson.dependencies || {}).filter(
38
- (dep) =>
39
- dep.startsWith('@akinon/') &&
40
- !installedPlugins.includes(dep.replace('@akinon/', '')) &&
41
- !protectedPackages.includes(dep)
42
- );
26
+ spawn.sync('yarn', ['cache clean']);
43
27
 
44
- pluginsToRemove.forEach((plugin) => {
45
- try {
46
- execSync(`yarn remove ${plugin}`, { stdio: 'inherit', cwd: BASE_DIR });
47
- } catch (error) {
48
- console.warn(
49
- `Warning: Could not remove ${plugin}. It may not have been installed.`
50
- );
51
- }
52
- });
28
+ for (const plugin of availablePlugins) {
29
+ spawn.sync('yarn', ['remove', `@akinon/${plugin}`]);
30
+ }
53
31
 
54
- installedPlugins.forEach((plugin) => {
55
- const packageName = `@akinon/${plugin}`;
56
- if (
57
- !Object.keys(packageJson.dependencies || {}).includes(packageName) &&
58
- !protectedPackages.includes(packageName)
59
- ) {
60
- try {
61
- const version = packageJson.dependencies['@akinon/next'].replace('^', '');
62
- const command = `yarn add ${packageName}@${version} --exact --ignore-scripts`;
63
- execSync(command, { stdio: 'inherit', cwd: BASE_DIR });
64
- } catch (error) {
65
- console.warn(
66
- '\n\x1b[33m%s\x1b[0m',
67
- `Error adding ${packageName}: ${error}`
68
- );
69
- }
70
- }
71
- });
32
+ if (
33
+ installCmd.length > 0 &&
34
+ !fs.existsSync(path.resolve(rootDir, '../../turbo.json'))
35
+ ) {
36
+ spawn.sync('yarn', ['add', ...installCmd, '--ignore-scripts'], {
37
+ stdio: 'inherit'
38
+ });
39
+ }
@@ -20,8 +20,6 @@ interface GetStockParams {
20
20
  }
21
21
 
22
22
  interface GetFavoritesResponse {
23
- next?: string | null;
24
- previous?: string | null;
25
23
  count: number;
26
24
  results: FavoriteItem[];
27
25
  }
@@ -15,7 +15,7 @@ function getCategoryDataHandler(
15
15
  const params = generateCommerceSearchParams(searchParams);
16
16
 
17
17
  const rawData = await appFetch<string>(
18
- `${category.getCategoryByPk(pk)}s${params ? params : ''}`,
18
+ `${category.getCategoryByPk(pk)}${params ? params : ''}`,
19
19
  {
20
20
  headers: {
21
21
  Accept: 'application/json',
@@ -39,7 +39,7 @@ function getCategoryDataHandler(
39
39
  numberValueParser
40
40
  ) as GetCategoryResponse;
41
41
  } catch (error) {
42
- logger.fatal('Error while parsing category data', {
42
+ logger.error('Error while parsing category data', {
43
43
  handler: 'getCategoryDataHandler',
44
44
  error,
45
45
  rawData: rawData.startsWith('<!DOCTYPE html>')
@@ -108,7 +108,7 @@ function getCategoryBySlugDataHandler(slug: string) {
108
108
  numberValueParser
109
109
  ) as GetCategoryResponse;
110
110
  } catch (error) {
111
- logger.fatal('Error while parsing category data', {
111
+ logger.error('Error while parsing category data', {
112
112
  handler: 'getCategoryBySlugDataHandler',
113
113
  error,
114
114
  rawData: rawData.startsWith('<!DOCTYPE html>')
@@ -38,7 +38,7 @@ const getListDataHandler = (
38
38
  numberValueParser
39
39
  ) as GetCategoryResponse;
40
40
  } catch (error) {
41
- logger.fatal('Error while parsing list data', {
41
+ logger.error('Error while parsing list data', {
42
42
  error,
43
43
  rawData: rawData.startsWith('<!DOCTYPE html>')
44
44
  ? `${rawData.substring(0, 50)}...`
@@ -70,6 +70,10 @@ export default function usePagination(
70
70
  dispatch({ type: 'setLimit', payload: limit });
71
71
  }, [limit]);
72
72
 
73
+ useEffect(() => {
74
+ window.scrollTo(0, 0);
75
+ }, [state.page, state.limit]);
76
+
73
77
  const setTotal = useCallback(
74
78
  (total: number) => {
75
79
  dispatch({ type: 'setTotal', payload: total });
package/lib/cache.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { createPool, Pool } from 'generic-pool';
2
1
  import { RedisClientType } from 'redis';
3
2
  import Settings from 'settings';
4
3
  import { CacheOptions } from '../types';
@@ -65,38 +64,21 @@ export class Cache {
65
64
  );
66
65
  }
67
66
 
68
- static clientPool: Pool<RedisClientType> = createPool(
69
- {
70
- create: async () => {
71
- const { createClient } = await import('redis');
72
- const redisUrl = `redis://${process.env.CACHE_HOST}:${
73
- process.env.CACHE_PORT
74
- }/${process.env.CACHE_BUCKET ?? '0'}`;
75
-
76
- const client: RedisClientType = createClient({
77
- url: redisUrl
78
- });
79
-
80
- client.on('error', (error) => {
81
- logger.error('Redis client error', { redisUrl, error });
82
- });
67
+ static async getClient() {
68
+ const { createClient } = await import('redis');
69
+ const redisUrl = `redis://${process.env.CACHE_HOST}:${
70
+ process.env.CACHE_PORT
71
+ }/${process.env.CACHE_BUCKET ?? '0'}`;
83
72
 
84
- await client.connect();
73
+ const client: RedisClientType = createClient({
74
+ url: redisUrl
75
+ });
85
76
 
86
- return client;
87
- },
88
- destroy: async (client: RedisClientType) => {
89
- await client.disconnect();
90
- }
91
- },
92
- {
93
- max: 500,
94
- min: 2
95
- }
96
- );
77
+ client.on('error', (error) => {
78
+ logger.error('Redis client error', { redisUrl, error });
79
+ });
97
80
 
98
- static async getClient() {
99
- return await Cache.clientPool.acquire();
81
+ return client;
100
82
  }
101
83
 
102
84
  static async get(key: string) {
@@ -105,49 +87,39 @@ export class Cache {
105
87
 
106
88
  try {
107
89
  client = await Cache.getClient();
108
- const response = await client.get(key);
109
- if (response) {
110
- value = JSON.parse(response);
111
- } else {
112
- value = null;
113
- }
114
- logger.debug('Redis get success', { key, value });
90
+ await client.connect();
91
+ value = JSON.parse(await client.get(key));
92
+
93
+ logger.debug('Redis get success', { key });
94
+ logger.trace('Redis get success', { key, value });
115
95
  } catch (error) {
116
96
  logger.error('Redis get error', { key, error });
117
- value = null;
118
97
  } finally {
119
- if (client) {
120
- await Cache.clientPool.release(client);
121
- }
98
+ await client?.disconnect();
122
99
  }
123
100
 
124
101
  return value;
125
102
  }
126
103
 
127
- static async set(key: string, value: any, expire?: number) {
104
+ static async set(key: string, value: string, expire?: number) {
128
105
  let success = false;
129
106
  let client;
130
107
 
131
108
  try {
132
109
  client = await Cache.getClient();
133
- const serializedValue =
134
- typeof value === 'object' ? JSON.stringify(value) : value;
135
-
136
- if (expire) {
137
- await client.set(key, serializedValue, { EX: expire });
138
- } else {
139
- await client.set(key, serializedValue);
140
- }
110
+ await client.connect();
111
+ await client.set(key, value, {
112
+ EX: expire
113
+ });
141
114
 
142
115
  success = true;
143
- logger.debug('Redis set success', { key, value });
116
+
117
+ logger.debug('Redis set success', { key });
118
+ logger.trace('Redis set success', { key, value });
144
119
  } catch (error) {
145
120
  logger.error('Redis set error', { key, error });
146
- success = false;
147
121
  } finally {
148
- if (client) {
149
- await Cache.clientPool.release(client);
150
- }
122
+ await client?.disconnect();
151
123
  }
152
124
 
153
125
  return success;
@@ -1,9 +1,7 @@
1
1
  import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
2
  import Settings from 'settings';
3
- import { ROUTES } from 'routes';
4
3
  import {
5
4
  PzNextRequest,
6
- withCheckoutProvider,
7
5
  withCompleteGpay,
8
6
  withCompleteMasterpass,
9
7
  withOauthLogin,
@@ -114,36 +112,6 @@ const withPzDefault =
114
112
  return NextResponse.redirect(redirectUrlWithLocale, 303);
115
113
  }
116
114
 
117
- if (req.nextUrl.pathname.startsWith('/orders/checkout-provider/')) {
118
- try {
119
- const data = await req.json();
120
-
121
- const request = await fetch(
122
- `${encodeURI(Settings.commerceUrl)}${url.pathname.replace(
123
- urlLocaleMatcherRegex,
124
- ''
125
- )}?${searchParams.toString()}`,
126
- {
127
- method: 'POST',
128
- body: JSON.stringify(data),
129
- next: {
130
- revalidate: 0
131
- },
132
- headers: {
133
- Cookie: req.headers.get('cookie') || '',
134
- Accept: 'application/json',
135
- 'Content-Type': 'application/json',
136
- 'X-Requested-With': 'XMLHttpRequest'
137
- }
138
- }
139
- );
140
-
141
- return NextResponse.json(await request.json());
142
- } catch (error) {
143
- return NextResponse.redirect(ROUTES.BASKET);
144
- }
145
- }
146
-
147
115
  req.middlewareParams = {
148
116
  commerceUrl,
149
117
  rewrites: {}
@@ -155,82 +123,64 @@ const withPzDefault =
155
123
  withPrettyUrl(
156
124
  withRedirectionPayment(
157
125
  withThreeDRedirection(
158
- withCheckoutProvider(
159
- withUrlRedirection(
160
- withCompleteGpay(
161
- withCompleteMasterpass(
162
- async (req: PzNextRequest, event: NextFetchEvent) => {
163
- let middlewareResult: NextResponse | void =
164
- NextResponse.next();
165
-
166
- try {
167
- const { locale, prettyUrl, currency } =
168
- req.middlewareParams.rewrites;
169
- const { defaultLocaleValue } =
170
- Settings.localization;
171
- const url = req.nextUrl.clone();
172
- const pathnameWithoutLocale = url.pathname.replace(
173
- urlLocaleMatcherRegex,
174
- ''
126
+ withUrlRedirection(
127
+ withCompleteGpay(
128
+ withCompleteMasterpass(
129
+ async (req: PzNextRequest, event: NextFetchEvent) => {
130
+ let middlewareResult: NextResponse | void =
131
+ NextResponse.next();
132
+
133
+ try {
134
+ const { locale, prettyUrl, currency } =
135
+ req.middlewareParams.rewrites;
136
+ const { defaultLocaleValue } = Settings.localization;
137
+ const url = req.nextUrl.clone();
138
+ const pathnameWithoutLocale = url.pathname.replace(
139
+ urlLocaleMatcherRegex,
140
+ ''
141
+ );
142
+
143
+ url.basePath = `/${commerceUrl}`;
144
+ url.pathname = `/${
145
+ locale.length ? `${locale}/` : ''
146
+ }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
147
+
148
+ Settings.rewrites.forEach((rewrite) => {
149
+ url.pathname = url.pathname.replace(
150
+ rewrite.source,
151
+ rewrite.destination
175
152
  );
153
+ });
176
154
 
177
- url.basePath = `/${commerceUrl}`;
178
- url.pathname = `/${
179
- locale.length ? `${locale}/` : ''
180
- }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
181
-
182
- Settings.rewrites.forEach((rewrite) => {
183
- url.pathname = url.pathname.replace(
184
- rewrite.source,
185
- rewrite.destination
186
- );
187
- });
188
-
189
- middlewareResult = (await middleware(
190
- req,
191
- event
192
- )) as NextResponse | void;
193
-
194
- // if middleware.ts has a return value for current url
195
- if (middlewareResult instanceof NextResponse) {
196
- // pz-override-response header is used to prevent 404 page for custom responses.
197
- if (
198
- middlewareResult.headers.get(
199
- 'pz-override-response'
200
- ) !== 'true'
201
- ) {
202
- middlewareResult.headers.set(
203
- 'x-middleware-rewrite',
204
- url.href
205
- );
206
- }
207
- } else {
208
- // if middleware.ts doesn't have a return value.
209
- // e.g. NextResponse.next() doesn't exist in middleware.ts
210
-
211
- middlewareResult = NextResponse.rewrite(url);
212
- }
155
+ middlewareResult = (await middleware(
156
+ req,
157
+ event
158
+ )) as NextResponse | void;
213
159
 
160
+ // if middleware.ts has a return value for current url
161
+ if (middlewareResult instanceof NextResponse) {
162
+ // pz-override-response header is used to prevent 404 page for custom responses.
214
163
  if (
215
- !url.pathname.startsWith(`/${currency}/orders`)
164
+ middlewareResult.headers.get(
165
+ 'pz-override-response'
166
+ ) !== 'true'
216
167
  ) {
217
- middlewareResult.cookies.set(
218
- 'pz-locale',
219
- locale?.length > 0
220
- ? locale
221
- : defaultLocaleValue,
222
- {
223
- sameSite: 'none',
224
- secure: true,
225
- expires: new Date(
226
- Date.now() + 1000 * 60 * 60 * 24 * 7
227
- ) // 7 days
228
- }
168
+ middlewareResult.headers.set(
169
+ 'x-middleware-rewrite',
170
+ url.href
229
171
  );
230
172
  }
173
+ } else {
174
+ // if middleware.ts doesn't have a return value.
175
+ // e.g. NextResponse.next() doesn't exist in middleware.ts
176
+
177
+ middlewareResult = NextResponse.rewrite(url);
178
+ }
179
+
180
+ if (!url.pathname.startsWith(`/${currency}/orders`)) {
231
181
  middlewareResult.cookies.set(
232
- 'pz-currency',
233
- currency,
182
+ 'pz-locale',
183
+ locale?.length > 0 ? locale : defaultLocaleValue,
234
184
  {
235
185
  sameSite: 'none',
236
186
  secure: true,
@@ -239,65 +189,74 @@ const withPzDefault =
239
189
  ) // 7 days
240
190
  }
241
191
  );
242
-
243
- if (
244
- req.cookies.get('pz-locale') &&
245
- req.cookies.get('pz-locale').value !== locale
246
- ) {
247
- logger.debug('Locale changed', {
248
- locale,
249
- oldLocale: req.cookies.get('pz-locale')?.value,
250
- ip
251
- });
192
+ }
193
+ middlewareResult.cookies.set(
194
+ 'pz-currency',
195
+ currency,
196
+ {
197
+ sameSite: 'none',
198
+ secure: true,
199
+ expires: new Date(
200
+ Date.now() + 1000 * 60 * 60 * 24 * 7
201
+ ) // 7 days
252
202
  }
203
+ );
204
+
205
+ if (
206
+ req.cookies.get('pz-locale') &&
207
+ req.cookies.get('pz-locale').value !== locale
208
+ ) {
209
+ logger.debug('Locale changed', {
210
+ locale,
211
+ oldLocale: req.cookies.get('pz-locale')?.value,
212
+ ip
213
+ });
214
+ }
253
215
 
216
+ middlewareResult.headers.set(
217
+ 'pz-url',
218
+ req.nextUrl.toString()
219
+ );
220
+
221
+ if (req.cookies.get('pz-set-currency')) {
222
+ middlewareResult.cookies.delete('pz-set-currency');
223
+ }
224
+
225
+ if (process.env.ACC_APP_VERSION) {
254
226
  middlewareResult.headers.set(
255
- 'pz-url',
256
- req.nextUrl.toString()
227
+ 'acc-app-version',
228
+ process.env.ACC_APP_VERSION
257
229
  );
230
+ }
258
231
 
259
- if (req.cookies.get('pz-set-currency')) {
260
- middlewareResult.cookies.delete(
261
- 'pz-set-currency'
262
- );
263
- }
232
+ // Set CSRF token if not set
233
+ try {
234
+ const url = `${Settings.commerceUrl}${user.csrfToken}`;
264
235
 
265
- if (process.env.ACC_APP_VERSION) {
266
- middlewareResult.headers.set(
267
- 'acc-app-version',
268
- process.env.ACC_APP_VERSION
236
+ if (!req.cookies.get('csrftoken')) {
237
+ const { csrf_token } = await (
238
+ await fetch(url)
239
+ ).json();
240
+ middlewareResult.cookies.set(
241
+ 'csrftoken',
242
+ csrf_token
269
243
  );
270
244
  }
271
-
272
- // Set CSRF token if not set
273
- try {
274
- const url = `${Settings.commerceUrl}${user.csrfToken}`;
275
-
276
- if (!req.cookies.get('csrftoken')) {
277
- const { csrf_token } = await (
278
- await fetch(url)
279
- ).json();
280
- middlewareResult.cookies.set(
281
- 'csrftoken',
282
- csrf_token
283
- );
284
- }
285
- } catch (error) {
286
- logger.error('CSRF Error', {
287
- error,
288
- ip
289
- });
290
- }
291
245
  } catch (error) {
292
- logger.error('withPzDefault Error', {
246
+ logger.error('CSRF Error', {
293
247
  error,
294
248
  ip
295
249
  });
296
250
  }
297
-
298
- return middlewareResult;
251
+ } catch (error) {
252
+ logger.error('withPzDefault Error', {
253
+ error,
254
+ ip
255
+ });
299
256
  }
300
- )
257
+
258
+ return middlewareResult;
259
+ }
301
260
  )
302
261
  )
303
262
  )
@@ -7,7 +7,6 @@ import withOauthLogin from './oauth-login';
7
7
  import withUrlRedirection from './url-redirection';
8
8
  import withCompleteGpay from './complete-gpay';
9
9
  import withCompleteMasterpass from './complete-masterpass';
10
- import withCheckoutProvider from './checkout-provider';
11
10
  import { NextRequest } from 'next/server';
12
11
 
13
12
  export {
@@ -19,8 +18,7 @@ export {
19
18
  withOauthLogin,
20
19
  withUrlRedirection,
21
20
  withCompleteGpay,
22
- withCompleteMasterpass,
23
- withCheckoutProvider
21
+ withCompleteMasterpass
24
22
  };
25
23
 
26
24
  export interface PzNextRequest extends NextRequest {
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": "1.21.0-rc.9",
4
+ "version": "1.21.0",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -14,14 +14,13 @@
14
14
  "pz-postdev": "bin/pz-postdev.js"
15
15
  },
16
16
  "dependencies": {
17
+ "@opentelemetry/sdk-node": "0.46.0",
17
18
  "@opentelemetry/exporter-trace-otlp-http": "0.46.0",
18
19
  "@opentelemetry/resources": "1.19.0",
19
- "@opentelemetry/sdk-node": "0.46.0",
20
- "@opentelemetry/sdk-trace-node": "1.19.0",
21
20
  "@opentelemetry/semantic-conventions": "1.19.0",
21
+ "@opentelemetry/sdk-trace-node": "1.19.0",
22
22
  "@reduxjs/toolkit": "1.9.7",
23
23
  "cross-spawn": "7.0.3",
24
- "generic-pool": "3.9.0",
25
24
  "react-redux": "8.1.3",
26
25
  "react-string-replace": "1.1.1",
27
26
  "redis": "4.5.1",
@@ -32,7 +31,7 @@
32
31
  "@typescript-eslint/eslint-plugin": "6.7.4",
33
32
  "@typescript-eslint/parser": "6.7.4",
34
33
  "eslint": "^8.14.0",
35
- "@akinon/eslint-plugin-projectzero": "1.21.0-rc.9",
34
+ "@akinon/eslint-plugin-projectzero": "1.21.0",
36
35
  "eslint-config-prettier": "8.5.0"
37
36
  }
38
37
  }
package/sentry/index.ts CHANGED
@@ -1,33 +1,27 @@
1
1
  import * as Sentry from '@sentry/nextjs';
2
- import settings from 'settings';
3
2
 
4
3
  const SENTRY_DSN: string =
5
- settings.sentryDsn ||
6
- process.env.SENTRY_DSN ||
7
- process.env.NEXT_PUBLIC_SENTRY_DSN;
4
+ process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
8
5
 
9
6
  export const initSentry = (
10
7
  type: 'Server' | 'Client' | 'Edge',
11
- options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {
12
- dsn: SENTRY_DSN,
13
- integrations: [],
14
- tracesSampleRate: 1.0
15
- }
8
+ options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {}
16
9
  ) => {
17
- const initOptions = {
18
- ...options,
10
+ // TODO: Handle options with ESLint rules
11
+
12
+ // TODO: Remove Zero Project DSN
13
+
14
+ Sentry.init({
15
+ dsn:
16
+ SENTRY_DSN ||
17
+ 'https://d8558ef8997543deacf376c7d8d7cf4b@o64293.ingest.sentry.io/4504338423742464',
19
18
  initialScope: {
20
19
  tags: {
21
- ...((
22
- options.initialScope as {
23
- tags?: Record<string, string>;
24
- }
25
- )?.tags ?? {}),
26
20
  APP_TYPE: 'ProjectZeroNext',
27
21
  TYPE: type
28
22
  }
29
- }
30
- };
31
-
32
- Sentry.init(initOptions);
23
+ },
24
+ tracesSampleRate: 1.0,
25
+ integrations: []
26
+ });
33
27
  };
package/types/index.ts CHANGED
@@ -71,12 +71,6 @@ export interface Currency {
71
71
 
72
72
  export interface Settings {
73
73
  commerceUrl: string;
74
- /**
75
- * This option allows you to track Sentry events on the client side, in addition to server and edge environments.
76
- *
77
- * It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
78
- */
79
- sentryDsn?: string;
80
74
  redis: {
81
75
  defaultExpirationTime: number;
82
76
  };
@@ -12,7 +12,7 @@ const appFetch = async <T>(
12
12
  url: RequestInfo,
13
13
  init: RequestInit = {},
14
14
  responseType = FetchResponseType.JSON
15
- ): Promise<T> => {
15
+ ) => {
16
16
  let response: T;
17
17
  let status: number;
18
18
  let ip = '';
@@ -28,7 +28,7 @@ const appFetch = async <T>(
28
28
 
29
29
  if (commerceUrl === 'default') {
30
30
  logger.error('Commerce URL is not set. Current value is "default"');
31
- throw new Error('Commerce URL is not set');
31
+ return undefined;
32
32
  }
33
33
 
34
34
  const requestURL = `${decodeURIComponent(commerceUrl)}${url}`;
@@ -48,30 +48,19 @@ const appFetch = async <T>(
48
48
  status = req.status;
49
49
  logger.debug(`FETCH END ${url}`, { status: req.status, ip });
50
50
 
51
- if (!req.ok) {
52
- throw new Error(`Request failed with status ${status}`);
53
- }
51
+ const rawData = await req.text();
54
52
 
55
53
  if (responseType === FetchResponseType.JSON) {
56
- response = (await req.json()) as T;
54
+ response = JSON.parse(rawData);
57
55
  } else {
58
- response = (await req.text()) as unknown as T;
56
+ response = rawData as unknown as T;
59
57
  }
60
58
 
61
59
  logger.trace(`FETCH RESPONSE`, { url, response, ip });
62
60
  } catch (error) {
63
- const logType = status === 500 ? 'fatal' : 'error';
64
-
65
61
  if (!url.toString().includes('/cms/seo/')) {
66
- logger[logType](`FETCH FAILED`, { url, status, error, ip });
62
+ logger.error(`FETCH FAILED`, { url, status, error, ip });
67
63
  }
68
-
69
- // throw the error if it's fatal, so it can be caught and handled at higher levels
70
- if (logType === 'fatal') {
71
- throw error;
72
- }
73
-
74
- return Promise.reject(error);
75
64
  }
76
65
 
77
66
  return response;
@@ -1,88 +0,0 @@
1
- import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
- import settings from 'settings';
3
- import { PzNextRequest } from '.';
4
- import logger from '../utils/log';
5
- import { urlLocaleMatcherRegex } from '../utils';
6
- import { getUrlPathWithLocale } from '../utils/localization';
7
-
8
- const withCheckoutProvider =
9
- (middleware: NextMiddleware) =>
10
- async (req: PzNextRequest, event: NextFetchEvent) => {
11
- const url = req.nextUrl.clone();
12
- const ip = req.headers.get('x-forwarded-for') ?? '';
13
- const pathnameWithoutLocale = url.pathname.replace(
14
- urlLocaleMatcherRegex,
15
- ''
16
- );
17
- const searchParams = new URLSearchParams(url.search);
18
-
19
- if (pathnameWithoutLocale.startsWith('/orders/checkout-provider/')) {
20
- try {
21
- const request = await fetch(
22
- `${encodeURI(settings.commerceUrl)}${url.pathname.replace(
23
- urlLocaleMatcherRegex,
24
- ''
25
- )}?${searchParams.toString()}`,
26
- {
27
- next: {
28
- revalidate: 0
29
- },
30
- headers: {
31
- Cookie: req.headers.get('cookie') || '',
32
- Accept: 'application/json',
33
- 'X-Requested-With': 'XMLHttpRequest'
34
- }
35
- }
36
- );
37
-
38
- return NextResponse.json(await request.json());
39
- } catch (error) {
40
- logger.error('withCheckoutProvider error', {
41
- error,
42
- ip
43
- });
44
- return NextResponse.next();
45
- }
46
- }
47
-
48
- if (pathnameWithoutLocale.startsWith('/orders/checkout-provider-cancel')) {
49
- try {
50
- const request = await fetch(
51
- `${settings.commerceUrl}${pathnameWithoutLocale}${url.search}`,
52
- {
53
- redirect: 'manual',
54
- next: {
55
- revalidate: 0
56
- },
57
- headers: {
58
- Cookie: req.headers.get('cookie') || ''
59
- }
60
- }
61
- );
62
-
63
- if (request.headers.get('location')) {
64
- const location = request.headers.get('location');
65
- const redirectUrl = new URL(
66
- request.headers.get('location'),
67
- location.startsWith('http') ? '' : process.env.NEXT_PUBLIC_URL
68
- );
69
-
70
- redirectUrl.pathname = getUrlPathWithLocale(
71
- redirectUrl.pathname,
72
- req.middlewareParams.rewrites.locale
73
- );
74
-
75
- return Response.redirect(redirectUrl.toString(), request.status);
76
- }
77
- } catch (error) {
78
- logger.error('withCheckoutProvider error', {
79
- error,
80
- ip
81
- });
82
- }
83
- }
84
-
85
- return middleware(req, event);
86
- };
87
-
88
- export default withCheckoutProvider;