@akinon/next 1.21.0-rc.0 → 1.21.0-rc.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.21.0-rc.2
4
+
5
+ ### Minor Changes
6
+
7
+ - 8075006: install plugins check the akinon version
8
+ - 32668ed: ZERO-2296: Implement Checkout Provider Middleware and Enhancements
9
+ - 29191da: ImageLoader supports crop none
10
+
11
+ ## 1.21.0-rc.1
12
+
13
+ ### Minor Changes
14
+
15
+ - e910b228: ZERO-2421: Upgrade next version to 14.1.0
16
+ - 1b4b0fa1: Redis connection change to connection pool
17
+
3
18
  ## 1.21.0-rc.0
4
19
 
5
20
  ### Minor Changes
package/api/auth.ts CHANGED
@@ -220,6 +220,17 @@ 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
+ }
223
234
  }
224
235
  };
225
236
  };
@@ -1,39 +1,40 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require('fs');
4
1
  const path = require('path');
5
- const rootDir = path.resolve(process.cwd());
6
2
  const spawn = require('cross-spawn');
7
- const availablePlugins = require('../plugins');
8
-
9
- let plugins;
10
3
 
11
- try {
12
- plugins = require(path.resolve(rootDir, './src/plugins.js'));
13
- } catch (error) {
14
- console.error('No plugins.js file found, skipping plugin installation.');
15
- process.exit(0);
4
+ function findBaseDir() {
5
+ const insideNodeModules = __dirname.includes('node_modules');
6
+ return insideNodeModules
7
+ ? path.resolve(__dirname, '../../../../')
8
+ : path.resolve(__dirname, '../../../apps/projectzeronext');
16
9
  }
17
10
 
18
- let installCmd = [];
11
+ const BASE_DIR = findBaseDir();
19
12
 
20
- availablePlugins
21
- .filter((p) => plugins?.includes(p))
22
- .forEach((name) => {
23
- installCmd.push(`@akinon/${name}`);
24
- });
13
+ const getFullPath = (relativePath) => path.join(BASE_DIR, relativePath);
25
14
 
26
- spawn.sync('yarn', ['cache clean']);
15
+ const packageJsonPath = getFullPath('package.json');
16
+ const akinonPackageNumber = require(packageJsonPath).dependencies[
17
+ '@akinon/next'
18
+ ].replace('^', '');
19
+ //just in case
27
20
 
28
- for (const plugin of availablePlugins) {
29
- spawn.sync('yarn', ['remove', `@akinon/${plugin}`]);
30
- }
21
+ const availablePlugins = require('../plugins');
22
+
23
+ let installCmd = availablePlugins.map(
24
+ (name) => `@akinon/${name}@${akinonPackageNumber}`
25
+ );
26
+
27
+ spawn.sync('yarn', ['cache clean'], { stdio: 'inherit', cwd: BASE_DIR });
31
28
 
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'
29
+ availablePlugins.forEach((plugin) => {
30
+ spawn.sync('yarn', ['remove', `@akinon/${plugin}`], {
31
+ stdio: 'inherit',
32
+ cwd: BASE_DIR
38
33
  });
34
+ });
35
+
36
+ if (installCmd.length > 0) {
37
+ const yarnArgs = ['add', ...installCmd, '--ignore-scripts'];
38
+
39
+ spawn.sync('yarn', yarnArgs, { stdio: 'inherit', cwd: BASE_DIR });
39
40
  }
package/lib/cache.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { createPool, Pool } from 'generic-pool';
1
2
  import { RedisClientType } from 'redis';
2
3
  import Settings from 'settings';
3
4
  import { CacheOptions } from '../types';
@@ -64,21 +65,38 @@ export class Cache {
64
65
  );
65
66
  }
66
67
 
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'}`;
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
+ });
72
79
 
73
- const client: RedisClientType = createClient({
74
- url: redisUrl
75
- });
80
+ client.on('error', (error) => {
81
+ logger.error('Redis client error', { redisUrl, error });
82
+ });
76
83
 
77
- client.on('error', (error) => {
78
- logger.error('Redis client error', { redisUrl, error });
79
- });
84
+ await client.connect();
85
+
86
+ return client;
87
+ },
88
+ destroy: async (client: RedisClientType) => {
89
+ await client.disconnect();
90
+ }
91
+ },
92
+ {
93
+ max: 500,
94
+ min: 2
95
+ }
96
+ );
80
97
 
81
- return client;
98
+ static async getClient() {
99
+ return await Cache.clientPool.acquire();
82
100
  }
83
101
 
84
102
  static async get(key: string) {
@@ -87,39 +105,49 @@ export class Cache {
87
105
 
88
106
  try {
89
107
  client = await Cache.getClient();
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 });
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 });
95
115
  } catch (error) {
96
116
  logger.error('Redis get error', { key, error });
117
+ value = null;
97
118
  } finally {
98
- await client?.disconnect();
119
+ if (client) {
120
+ await Cache.clientPool.release(client);
121
+ }
99
122
  }
100
123
 
101
124
  return value;
102
125
  }
103
126
 
104
- static async set(key: string, value: string, expire?: number) {
127
+ static async set(key: string, value: any, expire?: number) {
105
128
  let success = false;
106
129
  let client;
107
130
 
108
131
  try {
109
132
  client = await Cache.getClient();
110
- await client.connect();
111
- await client.set(key, value, {
112
- EX: expire
113
- });
133
+ const serializedValue =
134
+ typeof value === 'object' ? JSON.stringify(value) : value;
114
135
 
115
- success = true;
136
+ if (expire) {
137
+ await client.set(key, serializedValue, { EX: expire });
138
+ } else {
139
+ await client.set(key, serializedValue);
140
+ }
116
141
 
117
- logger.debug('Redis set success', { key });
118
- logger.trace('Redis set success', { key, value });
142
+ success = true;
143
+ logger.debug('Redis set success', { key, value });
119
144
  } catch (error) {
120
145
  logger.error('Redis set error', { key, error });
146
+ success = false;
121
147
  } finally {
122
- await client?.disconnect();
148
+ if (client) {
149
+ await Cache.clientPool.release(client);
150
+ }
123
151
  }
124
152
 
125
153
  return success;
@@ -0,0 +1,88 @@
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;
@@ -2,6 +2,7 @@ import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
2
  import Settings from 'settings';
3
3
  import {
4
4
  PzNextRequest,
5
+ withCheckoutProvider,
5
6
  withCompleteGpay,
6
7
  withCompleteMasterpass,
7
8
  withOauthLogin,
@@ -16,6 +17,7 @@ import withLocale from './locale';
16
17
  import logger from '../utils/log';
17
18
  import { user } from '../data/urls';
18
19
  import { getUrlPathWithLocale } from '../utils/localization';
20
+ import { ROUTES } from 'projectzeronext/src/routes';
19
21
 
20
22
  const withPzDefault =
21
23
  (middleware: NextMiddleware) =>
@@ -112,6 +114,36 @@ const withPzDefault =
112
114
  return NextResponse.redirect(redirectUrlWithLocale, 303);
113
115
  }
114
116
 
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
+
115
147
  req.middlewareParams = {
116
148
  commerceUrl,
117
149
  rewrites: {}
@@ -123,64 +155,82 @@ const withPzDefault =
123
155
  withPrettyUrl(
124
156
  withRedirectionPayment(
125
157
  withThreeDRedirection(
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
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
+ ''
152
175
  );
153
- });
154
176
 
155
- middlewareResult = (await middleware(
156
- req,
157
- event
158
- )) as NextResponse | void;
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
+ }
159
213
 
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.
163
214
  if (
164
- middlewareResult.headers.get(
165
- 'pz-override-response'
166
- ) !== 'true'
215
+ !url.pathname.startsWith(`/${currency}/orders`)
167
216
  ) {
168
- middlewareResult.headers.set(
169
- 'x-middleware-rewrite',
170
- url.href
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
+ }
171
229
  );
172
230
  }
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`)) {
181
231
  middlewareResult.cookies.set(
182
- 'pz-locale',
183
- locale?.length > 0 ? locale : defaultLocaleValue,
232
+ 'pz-currency',
233
+ currency,
184
234
  {
185
235
  sameSite: 'none',
186
236
  secure: true,
@@ -189,74 +239,65 @@ const withPzDefault =
189
239
  ) // 7 days
190
240
  }
191
241
  );
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
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
- }
215
-
216
- middlewareResult.headers.set(
217
- 'pz-url',
218
- req.nextUrl.toString()
219
- );
220
242
 
221
- if (req.cookies.get('pz-set-currency')) {
222
- middlewareResult.cookies.delete('pz-set-currency');
223
- }
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
+ });
252
+ }
224
253
 
225
- if (process.env.ACC_APP_VERSION) {
226
254
  middlewareResult.headers.set(
227
- 'acc-app-version',
228
- process.env.ACC_APP_VERSION
255
+ 'pz-url',
256
+ req.nextUrl.toString()
229
257
  );
230
- }
231
258
 
232
- // Set CSRF token if not set
233
- try {
234
- const url = `${Settings.commerceUrl}${user.csrfToken}`;
259
+ if (req.cookies.get('pz-set-currency')) {
260
+ middlewareResult.cookies.delete(
261
+ 'pz-set-currency'
262
+ );
263
+ }
235
264
 
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
265
+ if (process.env.ACC_APP_VERSION) {
266
+ middlewareResult.headers.set(
267
+ 'acc-app-version',
268
+ process.env.ACC_APP_VERSION
243
269
  );
244
270
  }
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
+ }
245
291
  } catch (error) {
246
- logger.error('CSRF Error', {
292
+ logger.error('withPzDefault Error', {
247
293
  error,
248
294
  ip
249
295
  });
250
296
  }
251
- } catch (error) {
252
- logger.error('withPzDefault Error', {
253
- error,
254
- ip
255
- });
256
- }
257
297
 
258
- return middlewareResult;
259
- }
298
+ return middlewareResult;
299
+ }
300
+ )
260
301
  )
261
302
  )
262
303
  )
@@ -7,6 +7,7 @@ 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';
10
11
  import { NextRequest } from 'next/server';
11
12
 
12
13
  export {
@@ -18,7 +19,8 @@ export {
18
19
  withOauthLogin,
19
20
  withUrlRedirection,
20
21
  withCompleteGpay,
21
- withCompleteMasterpass
22
+ withCompleteMasterpass,
23
+ withCheckoutProvider
22
24
  };
23
25
 
24
26
  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.0",
4
+ "version": "1.21.0-rc.2",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -14,13 +14,14 @@
14
14
  "pz-postdev": "bin/pz-postdev.js"
15
15
  },
16
16
  "dependencies": {
17
- "@opentelemetry/sdk-node": "0.46.0",
18
17
  "@opentelemetry/exporter-trace-otlp-http": "0.46.0",
19
18
  "@opentelemetry/resources": "1.19.0",
20
- "@opentelemetry/semantic-conventions": "1.19.0",
19
+ "@opentelemetry/sdk-node": "0.46.0",
21
20
  "@opentelemetry/sdk-trace-node": "1.19.0",
21
+ "@opentelemetry/semantic-conventions": "1.19.0",
22
22
  "@reduxjs/toolkit": "1.9.7",
23
23
  "cross-spawn": "7.0.3",
24
+ "generic-pool": "3.9.0",
24
25
  "react-redux": "8.1.3",
25
26
  "react-string-replace": "1.1.1",
26
27
  "redis": "4.5.1",
@@ -31,7 +32,7 @@
31
32
  "@typescript-eslint/eslint-plugin": "6.7.4",
32
33
  "@typescript-eslint/parser": "6.7.4",
33
34
  "eslint": "^8.14.0",
34
- "@akinon/eslint-plugin-projectzero": "1.21.0-rc.0",
35
+ "@akinon/eslint-plugin-projectzero": "1.21.0-rc.2",
35
36
  "eslint-config-prettier": "8.5.0"
36
37
  }
37
38
  }
package/types/index.ts CHANGED
@@ -198,7 +198,7 @@ export type CDNOptions = {
198
198
  width?: number;
199
199
  height?: number;
200
200
  quality?: number;
201
- crop?: 'center' | 'top' | 'bottom' | 'left' | 'right';
201
+ crop?: 'center' | 'top' | 'bottom' | 'left' | 'right' | 'none';
202
202
  upscale?: boolean;
203
203
  };
204
204
 
@@ -19,12 +19,19 @@ export const ImageLoader = ({
19
19
  aspectRatio
20
20
  }: ImageLoaderParams) => {
21
21
  if (src.match(/akinoncdn|akinoncloud|b-cdn\.net/)) {
22
- return buildCDNUrl(src, {
22
+ const height =
23
+ fill && aspectRatio
24
+ ? parseInt(String(Number(width) / aspectRatio))
25
+ : undefined;
26
+
27
+ const config: CDNOptions = {
23
28
  width,
24
- height: fill ? parseInt(String(Number(width) / aspectRatio)) : undefined,
29
+ height,
25
30
  quality,
26
- crop
27
- });
31
+ crop: crop !== 'none' ? crop : undefined
32
+ };
33
+
34
+ return buildCDNUrl(src, config);
28
35
  }
29
36
 
30
37
  return src;
package/with-pz-config.js CHANGED
@@ -3,7 +3,7 @@ const deepMerge = require('./utils/deep-merge');
3
3
 
4
4
  /** @type {import('next').NextConfig} */
5
5
  const defaultConfig = {
6
- experimental: { serverActions: true, instrumentationHook: true },
6
+ experimental: { instrumentationHook: true },
7
7
  reactStrictMode: true,
8
8
  transpilePackages: ['@akinon/next', ...pzPlugins.map((p) => `@akinon/${p}`)],
9
9
  skipTrailingSlashRedirect: true,