@websolutespa/bom-mixer-image 1.8.3 → 2.0.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,98 +1,110 @@
1
- # @websolutespa/bom-mixer-image
2
-
3
- ## 1.8.3
4
-
5
- ### Patch Changes
6
-
7
- - Added: ImageStrategy.Token
8
- - Updated dependencies
9
- - @websolutespa/bom-core@1.8.4
10
-
11
- ## 1.8.2
12
-
13
- ### Patch Changes
14
-
15
- - Modified: imageHandler
16
-
17
- ## 1.8.1
18
-
19
- ### Patch Changes
20
-
21
- - Modified: imageHandler
22
-
23
- ## 1.8.0
24
-
25
- ### Patch Changes
26
-
27
- - Updated dependencies [f8a1d97]
28
- - @websolutespa/bom-core@1.8.0
29
-
30
- ## 1.0.9
31
-
32
- ### Patch Changes
33
-
34
- - Fixing: downgrading eslint to v8.56.0
35
- - Updated dependencies
36
- - @websolutespa/bom-core@1.7.8
37
-
38
- ## 1.0.8
39
-
40
- ### Patch Changes
41
-
42
- - Added: Cache-Control
43
-
44
- ## 1.0.7
45
-
46
- ### Patch Changes
47
-
48
- - Fixing: imageHandler Vercel support
49
- - Updated dependencies
50
- - @websolutespa/bom-core@1.7.7
51
-
52
- ## 1.0.6
53
-
54
- ### Patch Changes
55
-
56
- - Modified: imageHandler, re-route not found to origin
57
-
58
- ## 1.0.5
59
-
60
- ### Patch Changes
61
-
62
- - Modified: imageHandler
63
- - Updated dependencies
64
- - @websolutespa/bom-core@1.7.6
65
-
66
- ## 1.0.4
67
-
68
- ### Patch Changes
69
-
70
- - Modified: imageHandler getOriginalImage
71
- - Updated dependencies
72
- - @websolutespa/bom-core@1.7.5
73
-
74
- ## 1.0.3
75
-
76
- ### Patch Changes
77
-
78
- - 43957d4: Fixing: production local asset public path
79
- - Updated dependencies
80
- - @websolutespa/bom-core@1.7.4
81
-
82
- ## 1.0.2
83
-
84
- ### Patch Changes
85
-
86
- - 75b1311: Fixing: relative paths
87
-
88
- ## 1.0.1
89
-
90
- ### Patch Changes
91
-
92
- - Updating: dependencies
93
-
94
- ## 1.0.0
95
-
96
- ### Patch Changes
97
-
98
- - Added: first release
1
+ # @websolutespa/bom-mixer-image
2
+
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Release: Bom 2.0
8
+
9
+ ## 1.8.4
10
+
11
+ ### Patch Changes
12
+
13
+ - Fixing: handling latin1 src
14
+
15
+ ## 1.8.3
16
+
17
+ ### Patch Changes
18
+
19
+ - Added: ImageStrategy.Token
20
+ - Updated dependencies
21
+ - @websolutespa/bom-core@1.8.4
22
+
23
+ ## 1.8.2
24
+
25
+ ### Patch Changes
26
+
27
+ - Modified: imageHandler
28
+
29
+ ## 1.8.1
30
+
31
+ ### Patch Changes
32
+
33
+ - Modified: imageHandler
34
+
35
+ ## 1.8.0
36
+
37
+ ### Patch Changes
38
+
39
+ - Updated dependencies [f8a1d97]
40
+ - @websolutespa/bom-core@1.8.0
41
+
42
+ ## 1.0.9
43
+
44
+ ### Patch Changes
45
+
46
+ - Fixing: downgrading eslint to v8.56.0
47
+ - Updated dependencies
48
+ - @websolutespa/bom-core@1.7.8
49
+
50
+ ## 1.0.8
51
+
52
+ ### Patch Changes
53
+
54
+ - Added: Cache-Control
55
+
56
+ ## 1.0.7
57
+
58
+ ### Patch Changes
59
+
60
+ - Fixing: imageHandler Vercel support
61
+ - Updated dependencies
62
+ - @websolutespa/bom-core@1.7.7
63
+
64
+ ## 1.0.6
65
+
66
+ ### Patch Changes
67
+
68
+ - Modified: imageHandler, re-route not found to origin
69
+
70
+ ## 1.0.5
71
+
72
+ ### Patch Changes
73
+
74
+ - Modified: imageHandler
75
+ - Updated dependencies
76
+ - @websolutespa/bom-core@1.7.6
77
+
78
+ ## 1.0.4
79
+
80
+ ### Patch Changes
81
+
82
+ - Modified: imageHandler getOriginalImage
83
+ - Updated dependencies
84
+ - @websolutespa/bom-core@1.7.5
85
+
86
+ ## 1.0.3
87
+
88
+ ### Patch Changes
89
+
90
+ - 43957d4: Fixing: production local asset public path
91
+ - Updated dependencies
92
+ - @websolutespa/bom-core@1.7.4
93
+
94
+ ## 1.0.2
95
+
96
+ ### Patch Changes
97
+
98
+ - 75b1311: Fixing: relative paths
99
+
100
+ ## 1.0.1
101
+
102
+ ### Patch Changes
103
+
104
+ - Updating: dependencies
105
+
106
+ ## 1.0.0
107
+
108
+ ### Patch Changes
109
+
110
+ - Added: first release
package/dist/index.js CHANGED
@@ -100,10 +100,7 @@ function imageHandler({
100
100
  response.setHeader("Cache-Control", `public, max-age=${IMAGE_MAX_AGE}`);
101
101
  return response.send(cachedImage);
102
102
  }
103
- const { headers } = request;
104
- const referer = headers.referer;
105
- const publicUrl = process.env.NEXT_PUBLIC_URL || "";
106
- if (referer && publicUrl !== "https://" && referer.indexOf(publicUrl) !== 0) {
103
+ if (isInvalidReferer(request)) {
107
104
  return response.status(401).send("you are not authorized to perform this action");
108
105
  }
109
106
  if (imageOptions.url.indexOf("http") === -1 && isVercel()) {
@@ -111,7 +108,9 @@ function imageHandler({
111
108
  }
112
109
  const originalImageBuffer = await getOriginalImage(imageOptions.url, domains, request.headers);
113
110
  if (originalImageBuffer) {
114
- const originalImage = (0, import_sharp.default)(originalImageBuffer);
111
+ const originalImage = (0, import_sharp.default)(originalImageBuffer, {
112
+ animated: isGIF(imageOptions.url)
113
+ });
115
114
  const resizedImage = await resizeImage(originalImage, imageOptions);
116
115
  const compressedImage = resizedImage.webp({
117
116
  quality: imageOptions.q
@@ -135,6 +134,18 @@ function imageHandler({
135
134
  }
136
135
  });
137
136
  }
137
+ function isGIF(src) {
138
+ return src.indexOf(".gif") !== -1;
139
+ }
140
+ function isInvalidReferer(request) {
141
+ const { headers } = request;
142
+ const referer = headers.referer;
143
+ const publicUrl = process.env.NEXT_PUBLIC_URL || "";
144
+ if (IMAGE_STRATEGY !== import_bom_core.ImageStrategy.Token && referer && publicUrl !== "https://" && referer.indexOf(publicUrl) !== 0) {
145
+ return true;
146
+ }
147
+ return false;
148
+ }
138
149
  function getImageOptions(request, options) {
139
150
  const { slugs, origin = "", search = "", w, h, x, y, q } = request.query;
140
151
  if (!Array.isArray(slugs) || slugs.length === 0) {
@@ -183,9 +194,10 @@ function getEncryptedImageOptions(request, options) {
183
194
  throw "missing t parameter";
184
195
  }
185
196
  const imageResize = (0, import_bom_core.decryptImageResize)(t);
186
- const url = origin + "/" + slugs.join("/") + search;
197
+ imageResize.src = decodeURIComponent(imageResize.src);
198
+ const url = decodeURIComponent(origin + "/" + slugs.join("/") + search);
187
199
  if (imageResize.src !== url) {
188
- throw "invalid src parameter";
200
+ throw `invalid src parameter ${imageResize.src} ${url}`;
189
201
  }
190
202
  return {
191
203
  ...imageResize,
@@ -245,10 +257,10 @@ async function resizeImage(originalImage, imageOptions) {
245
257
  return defaultResizeOptions();
246
258
  }
247
259
  }
248
- function getOriginalImage(url, domains, headers, skipUrlValidity = false) {
260
+ function getOriginalImage(url, domains, headers) {
249
261
  return new Promise((resolve, reject) => {
250
262
  if (url.indexOf("http") === 0) {
251
- if (!skipUrlValidity && !checkUrlValidity(url, domains)) {
263
+ if (isInvalidDomain(url, domains)) {
252
264
  return reject({ status: 401, message: "invalid origin" });
253
265
  }
254
266
  fetch(url, {
@@ -311,9 +323,12 @@ function urlToCachedName(options) {
311
323
  const cachedName = options.h ? path.join(cacheDir, `${parsedName.name}_w_${options.w}_h_${options.h || 0}_x_${options.x || IMAGE_FOCAL_X}_y_${options.y || IMAGE_FOCAL_Y}_q_${options.q}${parsedName.ext}`) : path.join(cacheDir, `${parsedName.name}_w_${options.w}_q_${options.q}${parsedName.ext}`);
312
324
  return cachedName;
313
325
  }
314
- function checkUrlValidity(src, domains) {
326
+ function isInvalidDomain(src, domains) {
327
+ if (IMAGE_STRATEGY === import_bom_core.ImageStrategy.Token) {
328
+ return false;
329
+ }
315
330
  const url = new URL(src);
316
- return domains.includes(url.hostname);
331
+ return !domains.includes(url.hostname);
317
332
  }
318
333
  // Annotate the CommonJS export names for ESM import in node:
319
334
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -64,10 +64,7 @@ function imageHandler({
64
64
  response.setHeader("Cache-Control", `public, max-age=${IMAGE_MAX_AGE}`);
65
65
  return response.send(cachedImage);
66
66
  }
67
- const { headers } = request;
68
- const referer = headers.referer;
69
- const publicUrl = process.env.NEXT_PUBLIC_URL || "";
70
- if (referer && publicUrl !== "https://" && referer.indexOf(publicUrl) !== 0) {
67
+ if (isInvalidReferer(request)) {
71
68
  return response.status(401).send("you are not authorized to perform this action");
72
69
  }
73
70
  if (imageOptions.url.indexOf("http") === -1 && isVercel()) {
@@ -75,7 +72,9 @@ function imageHandler({
75
72
  }
76
73
  const originalImageBuffer = await getOriginalImage(imageOptions.url, domains, request.headers);
77
74
  if (originalImageBuffer) {
78
- const originalImage = sharp(originalImageBuffer);
75
+ const originalImage = sharp(originalImageBuffer, {
76
+ animated: isGIF(imageOptions.url)
77
+ });
79
78
  const resizedImage = await resizeImage(originalImage, imageOptions);
80
79
  const compressedImage = resizedImage.webp({
81
80
  quality: imageOptions.q
@@ -99,6 +98,18 @@ function imageHandler({
99
98
  }
100
99
  });
101
100
  }
101
+ function isGIF(src) {
102
+ return src.indexOf(".gif") !== -1;
103
+ }
104
+ function isInvalidReferer(request) {
105
+ const { headers } = request;
106
+ const referer = headers.referer;
107
+ const publicUrl = process.env.NEXT_PUBLIC_URL || "";
108
+ if (IMAGE_STRATEGY !== ImageStrategy.Token && referer && publicUrl !== "https://" && referer.indexOf(publicUrl) !== 0) {
109
+ return true;
110
+ }
111
+ return false;
112
+ }
102
113
  function getImageOptions(request, options) {
103
114
  const { slugs, origin = "", search = "", w, h, x, y, q } = request.query;
104
115
  if (!Array.isArray(slugs) || slugs.length === 0) {
@@ -147,9 +158,10 @@ function getEncryptedImageOptions(request, options) {
147
158
  throw "missing t parameter";
148
159
  }
149
160
  const imageResize = decryptImageResize(t);
150
- const url = origin + "/" + slugs.join("/") + search;
161
+ imageResize.src = decodeURIComponent(imageResize.src);
162
+ const url = decodeURIComponent(origin + "/" + slugs.join("/") + search);
151
163
  if (imageResize.src !== url) {
152
- throw "invalid src parameter";
164
+ throw `invalid src parameter ${imageResize.src} ${url}`;
153
165
  }
154
166
  return {
155
167
  ...imageResize,
@@ -209,10 +221,10 @@ async function resizeImage(originalImage, imageOptions) {
209
221
  return defaultResizeOptions();
210
222
  }
211
223
  }
212
- function getOriginalImage(url, domains, headers, skipUrlValidity = false) {
224
+ function getOriginalImage(url, domains, headers) {
213
225
  return new Promise((resolve, reject) => {
214
226
  if (url.indexOf("http") === 0) {
215
- if (!skipUrlValidity && !checkUrlValidity(url, domains)) {
227
+ if (isInvalidDomain(url, domains)) {
216
228
  return reject({ status: 401, message: "invalid origin" });
217
229
  }
218
230
  fetch(url, {
@@ -275,9 +287,12 @@ function urlToCachedName(options) {
275
287
  const cachedName = options.h ? path.join(cacheDir, `${parsedName.name}_w_${options.w}_h_${options.h || 0}_x_${options.x || IMAGE_FOCAL_X}_y_${options.y || IMAGE_FOCAL_Y}_q_${options.q}${parsedName.ext}`) : path.join(cacheDir, `${parsedName.name}_w_${options.w}_q_${options.q}${parsedName.ext}`);
276
288
  return cachedName;
277
289
  }
278
- function checkUrlValidity(src, domains) {
290
+ function isInvalidDomain(src, domains) {
291
+ if (IMAGE_STRATEGY === ImageStrategy.Token) {
292
+ return false;
293
+ }
279
294
  const url = new URL(src);
280
- return domains.includes(url.hostname);
295
+ return !domains.includes(url.hostname);
281
296
  }
282
297
  export {
283
298
  imageHandler
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websolutespa/bom-mixer-image",
3
- "version": "1.8.3",
3
+ "version": "2.0.0",
4
4
  "description": "Mixer Image module of the BOM Repository",
5
5
  "keywords": [
6
6
  "bom",
@@ -24,17 +24,17 @@
24
24
  },
25
25
  "dependencies": {},
26
26
  "peerDependencies": {
27
- "@websolutespa/bom-core": "*",
27
+ "@websolutespa/bom-core": "^2.0.0",
28
28
  "next": ">= 14.1.4",
29
29
  "sharp": ">= 0.30.4"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/sharp": "^0.30.4",
33
- "@websolutespa/bom-cli": "*",
34
- "@websolutespa/test": "*",
35
- "@websolutespa/tsconfig": "*",
33
+ "@websolutespa/bom-cli": "^2.0.0",
34
+ "@websolutespa/test": "^2.0.0",
35
+ "@websolutespa/tsconfig": "^2.0.0",
36
36
  "eslint": "^8.56.0",
37
- "eslint-config-websolute": "*",
37
+ "eslint-config-websolute": "^2.0.0",
38
38
  "npm-run-all": "^4.1.5",
39
39
  "sharp": "0.30.4",
40
40
  "ts-node": "^10.9.1",
@@ -72,15 +72,7 @@ export function imageHandler({
72
72
  return response.send(cachedImage);
73
73
  }
74
74
  // Check referrer
75
- const { headers } = request;
76
- const referer = headers.referer;
77
- const publicUrl = process.env.NEXT_PUBLIC_URL || '';
78
- // console.log('referef', referer, 'publicUrl', publicUrl);
79
- if (
80
- referer &&
81
- publicUrl !== 'https://' &&
82
- referer.indexOf(publicUrl) !== 0
83
- ) {
75
+ if (isInvalidReferer(request)) {
84
76
  return response.status(401).send('you are not authorized to perform this action');
85
77
  }
86
78
  // Temporarily fix Vercel local image issue
@@ -92,7 +84,9 @@ export function imageHandler({
92
84
  // Checking if the original image exists
93
85
  if (originalImageBuffer) {
94
86
  // Original image
95
- const originalImage = sharp(originalImageBuffer);
87
+ const originalImage = sharp(originalImageBuffer, {
88
+ animated: isGIF(imageOptions.url),
89
+ });
96
90
  // Resizing the original image and converting it to WebP format
97
91
  const resizedImage = await resizeImage(originalImage, imageOptions);
98
92
  // Converting resized image to WebP format
@@ -129,6 +123,26 @@ export function imageHandler({
129
123
  });
130
124
  }
131
125
 
126
+ function isGIF(src: string): boolean {
127
+ return src.indexOf('.gif') !== -1;
128
+ }
129
+
130
+ function isInvalidReferer(request: NextApiRequest): boolean {
131
+ const { headers } = request;
132
+ const referer = headers.referer;
133
+ const publicUrl = process.env.NEXT_PUBLIC_URL || '';
134
+ // console.log('referef', referer, 'publicUrl', publicUrl, 'IMAGE_STRATEGY', IMAGE_STRATEGY, ImageStrategy.Token);
135
+ if (
136
+ IMAGE_STRATEGY !== ImageStrategy.Token &&
137
+ referer &&
138
+ publicUrl !== 'https://' &&
139
+ referer.indexOf(publicUrl) !== 0
140
+ ) {
141
+ return true;
142
+ }
143
+ return false;
144
+ }
145
+
132
146
  function getImageOptions(request: NextApiRequest, options: IImageHandlerOptions): IImageOptions {
133
147
  // Destructuring 'slugs', 'origin', 'search', 'w', 'h', 'x', 'y', 'q' from the request query
134
148
  const { slugs, origin = '', search = '', w, h, x, y, q } = request.query;
@@ -211,11 +225,12 @@ function getEncryptedImageOptions(request: NextApiRequest, options: IImageHandle
211
225
  throw 'invalid q parameter';
212
226
  }
213
227
  */
228
+ imageResize.src = decodeURIComponent(imageResize.src);
214
229
  // Generating url
215
- const url = origin + '/' + slugs.join('/') + search;
230
+ const url = decodeURIComponent(origin + '/' + slugs.join('/') + search);
216
231
  //
217
232
  if (imageResize.src !== url) {
218
- throw 'invalid src parameter';
233
+ throw `invalid src parameter ${imageResize.src} ${url}`;
219
234
  }
220
235
  //
221
236
  return {
@@ -285,16 +300,12 @@ async function resizeImage(originalImage: sharp.Sharp, imageOptions: IImageOptio
285
300
  }
286
301
 
287
302
  // Defining the 'getOriginalImage' function
288
- function getOriginalImage(url: string, domains: string[], headers: IncomingHttpHeaders, skipUrlValidity: boolean = false): Promise<Buffer> {
303
+ function getOriginalImage(url: string, domains: string[], headers: IncomingHttpHeaders): Promise<Buffer> {
289
304
  // Returning a new promise
290
305
  return new Promise((resolve, reject) => {
291
306
  // Checking if 'url' starts with 'http'
292
307
  if (url.indexOf('http') === 0) {
293
- if (
294
- !skipUrlValidity &&
295
- !checkUrlValidity(url, domains)
296
- ) {
297
- // console.error('imageHandler.getOriginalImage.error invalid origin');
308
+ if (isInvalidDomain(url, domains)) {
298
309
  return reject({ status: 401, message: 'invalid origin' });
299
310
  }
300
311
  // Fetching the image from the URL
@@ -330,21 +341,6 @@ function getOriginalImage(url: string, domains: string[], headers: IncomingHttpH
330
341
  // Resolving the promise with the image data
331
342
  return resolve(data);
332
343
  });
333
- /*
334
- // Check if the file exists
335
- if (fs.existsSync(filePath)) {
336
- fs.readFile(filePath, (error, data) => {
337
- if (error) {
338
- return reject(error);
339
- }
340
- // Resolving the promise with the image data
341
- return resolve(data);
342
- });
343
- } else {
344
- const origin = getOrigin(headers);
345
- return getOriginalImage(`${origin}${url}`, domains, headers, true);
346
- }
347
- */
348
344
  }
349
345
  });
350
346
  }
@@ -407,7 +403,10 @@ function urlToCachedName(options: IImageOptions): string {
407
403
  return cachedName;
408
404
  }
409
405
 
410
- function checkUrlValidity(src: string, domains: string[]): boolean {
406
+ function isInvalidDomain(src: string, domains: string[]): boolean {
407
+ if (IMAGE_STRATEGY === ImageStrategy.Token) {
408
+ return false;
409
+ }
411
410
  const url = new URL(src);
412
- return domains.includes(url.hostname);
411
+ return !domains.includes(url.hostname);
413
412
  }