@websolutespa/bom-mixer-image 1.8.3 → 2.0.1-next.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,115 @@
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.1-next.0
4
+
5
+ ### Major Changes
6
+
7
+ - e74b305: Release: Payload 3.7.0
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [e74b305]
12
+ - @websolutespa/bom-core@2.0.1-next.0
13
+
14
+ ## 1.8.4
15
+
16
+ ### Patch Changes
17
+
18
+ - Fixing: handling latin1 src
19
+
20
+ ## 1.8.3
21
+
22
+ ### Patch Changes
23
+
24
+ - Added: ImageStrategy.Token
25
+ - Updated dependencies
26
+ - @websolutespa/bom-core@1.8.4
27
+
28
+ ## 1.8.2
29
+
30
+ ### Patch Changes
31
+
32
+ - Modified: imageHandler
33
+
34
+ ## 1.8.1
35
+
36
+ ### Patch Changes
37
+
38
+ - Modified: imageHandler
39
+
40
+ ## 1.8.0
41
+
42
+ ### Patch Changes
43
+
44
+ - Updated dependencies [f8a1d97]
45
+ - @websolutespa/bom-core@1.8.0
46
+
47
+ ## 1.0.9
48
+
49
+ ### Patch Changes
50
+
51
+ - Fixing: downgrading eslint to v8.56.0
52
+ - Updated dependencies
53
+ - @websolutespa/bom-core@1.7.8
54
+
55
+ ## 1.0.8
56
+
57
+ ### Patch Changes
58
+
59
+ - Added: Cache-Control
60
+
61
+ ## 1.0.7
62
+
63
+ ### Patch Changes
64
+
65
+ - Fixing: imageHandler Vercel support
66
+ - Updated dependencies
67
+ - @websolutespa/bom-core@1.7.7
68
+
69
+ ## 1.0.6
70
+
71
+ ### Patch Changes
72
+
73
+ - Modified: imageHandler, re-route not found to origin
74
+
75
+ ## 1.0.5
76
+
77
+ ### Patch Changes
78
+
79
+ - Modified: imageHandler
80
+ - Updated dependencies
81
+ - @websolutespa/bom-core@1.7.6
82
+
83
+ ## 1.0.4
84
+
85
+ ### Patch Changes
86
+
87
+ - Modified: imageHandler getOriginalImage
88
+ - Updated dependencies
89
+ - @websolutespa/bom-core@1.7.5
90
+
91
+ ## 1.0.3
92
+
93
+ ### Patch Changes
94
+
95
+ - 43957d4: Fixing: production local asset public path
96
+ - Updated dependencies
97
+ - @websolutespa/bom-core@1.7.4
98
+
99
+ ## 1.0.2
100
+
101
+ ### Patch Changes
102
+
103
+ - 75b1311: Fixing: relative paths
104
+
105
+ ## 1.0.1
106
+
107
+ ### Patch Changes
108
+
109
+ - Updating: dependencies
110
+
111
+ ## 1.0.0
112
+
113
+ ### Patch Changes
114
+
115
+ - Added: first release
@@ -1,8 +1,44 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ imageHandler: () => imageHandler
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
1
37
  // src/image/image.handler.ts
2
- import * as fs from "fs";
3
- import * as path from "path";
4
- import sharp from "sharp";
5
- import { decryptImageResize, ImageStrategy } from "@websolutespa/bom-core";
38
+ var fs = __toESM(require("fs"), 1);
39
+ var path = __toESM(require("path"), 1);
40
+ var import_sharp = __toESM(require("sharp"), 1);
41
+ var import_bom_core = require("@websolutespa/bom-core");
6
42
 
7
43
  // src/api/api.handler.ts
8
44
  function apiHandler(handler) {
@@ -32,7 +68,7 @@ function errorHandler(error, response) {
32
68
  }
33
69
 
34
70
  // src/image/image.handler.ts
35
- var IMAGE_STRATEGY = process.env.IMAGE_STRATEGY ? process.env.IMAGE_STRATEGY : ImageStrategy.Mixer;
71
+ var IMAGE_STRATEGY = process.env.IMAGE_STRATEGY ? process.env.IMAGE_STRATEGY : import_bom_core.ImageStrategy.Mixer;
36
72
  var IMAGE_MAX_AGE = 604800;
37
73
  var IMAGE_FOCAL_X = 50;
38
74
  var IMAGE_FOCAL_Y = 50;
@@ -48,7 +84,7 @@ function imageHandler({
48
84
  try {
49
85
  let imageOptions;
50
86
  try {
51
- imageOptions = IMAGE_STRATEGY === ImageStrategy.Token ? getEncryptedImageOptions(request, { domains, sizes, quality }) : getImageOptions(request, { domains, sizes, quality });
87
+ imageOptions = IMAGE_STRATEGY === import_bom_core.ImageStrategy.Token ? getEncryptedImageOptions(request, { domains, sizes, quality }) : getImageOptions(request, { domains, sizes, quality });
52
88
  } catch (error) {
53
89
  return response.status(400).json({
54
90
  errors: [{
@@ -64,10 +100,7 @@ function imageHandler({
64
100
  response.setHeader("Cache-Control", `public, max-age=${IMAGE_MAX_AGE}`);
65
101
  return response.send(cachedImage);
66
102
  }
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) {
103
+ if (isInvalidReferer(request)) {
71
104
  return response.status(401).send("you are not authorized to perform this action");
72
105
  }
73
106
  if (imageOptions.url.indexOf("http") === -1 && isVercel()) {
@@ -75,7 +108,9 @@ function imageHandler({
75
108
  }
76
109
  const originalImageBuffer = await getOriginalImage(imageOptions.url, domains, request.headers);
77
110
  if (originalImageBuffer) {
78
- const originalImage = sharp(originalImageBuffer);
111
+ const originalImage = (0, import_sharp.default)(originalImageBuffer, {
112
+ animated: isGIF(imageOptions.url)
113
+ });
79
114
  const resizedImage = await resizeImage(originalImage, imageOptions);
80
115
  const compressedImage = resizedImage.webp({
81
116
  quality: imageOptions.q
@@ -99,6 +134,18 @@ function imageHandler({
99
134
  }
100
135
  });
101
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
+ }
102
149
  function getImageOptions(request, options) {
103
150
  const { slugs, origin = "", search = "", w, h, x, y, q } = request.query;
104
151
  if (!Array.isArray(slugs) || slugs.length === 0) {
@@ -146,10 +193,11 @@ function getEncryptedImageOptions(request, options) {
146
193
  if (typeof t !== "string") {
147
194
  throw "missing t parameter";
148
195
  }
149
- const imageResize = decryptImageResize(t);
150
- const url = origin + "/" + slugs.join("/") + search;
196
+ const imageResize = (0, import_bom_core.decryptImageResize)(t);
197
+ imageResize.src = decodeURIComponent(imageResize.src);
198
+ const url = decodeURIComponent(origin + "/" + slugs.join("/") + search);
151
199
  if (imageResize.src !== url) {
152
- throw "invalid src parameter";
200
+ throw `invalid src parameter ${imageResize.src} ${url}`;
153
201
  }
154
202
  return {
155
203
  ...imageResize,
@@ -164,8 +212,8 @@ async function resizeImage(originalImage, imageOptions) {
164
212
  return originalImage.resize({
165
213
  width: resizeWidth,
166
214
  height: resizeHeight ? resizeHeight : void 0,
167
- fit: sharp.fit.cover,
168
- position: sharp.strategy.attention,
215
+ fit: import_sharp.default.fit.cover,
216
+ position: import_sharp.default.strategy.attention,
169
217
  withoutEnlargement: true
170
218
  });
171
219
  };
@@ -178,10 +226,10 @@ async function resizeImage(originalImage, imageOptions) {
178
226
  const imageToResize = originalImage.clone();
179
227
  const scaledImage = imageToResize.resize(prioritizeHeight ? {
180
228
  height: resizeHeight,
181
- fit: sharp.fit.cover
229
+ fit: import_sharp.default.fit.cover
182
230
  } : {
183
231
  width: resizeWidth,
184
- fit: sharp.fit.cover
232
+ fit: import_sharp.default.fit.cover
185
233
  });
186
234
  const { info: scaledImageInfo } = await scaledImage.toBuffer({ resolveWithObject: true });
187
235
  const extractWidth = resizeWidth ?? scaledImageInfo.width;
@@ -209,10 +257,10 @@ async function resizeImage(originalImage, imageOptions) {
209
257
  return defaultResizeOptions();
210
258
  }
211
259
  }
212
- function getOriginalImage(url, domains, headers, skipUrlValidity = false) {
260
+ function getOriginalImage(url, domains, headers) {
213
261
  return new Promise((resolve, reject) => {
214
262
  if (url.indexOf("http") === 0) {
215
- if (!skipUrlValidity && !checkUrlValidity(url, domains)) {
263
+ if (isInvalidDomain(url, domains)) {
216
264
  return reject({ status: 401, message: "invalid origin" });
217
265
  }
218
266
  fetch(url, {
@@ -275,10 +323,14 @@ function urlToCachedName(options) {
275
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}`);
276
324
  return cachedName;
277
325
  }
278
- function checkUrlValidity(src, domains) {
326
+ function isInvalidDomain(src, domains) {
327
+ if (IMAGE_STRATEGY === import_bom_core.ImageStrategy.Token) {
328
+ return false;
329
+ }
279
330
  const url = new URL(src);
280
- return domains.includes(url.hostname);
331
+ return !domains.includes(url.hostname);
281
332
  }
282
- export {
333
+ // Annotate the CommonJS export names for ESM import in node:
334
+ 0 && (module.exports = {
283
335
  imageHandler
284
- };
336
+ });
@@ -0,0 +1,15 @@
1
+ import { IImageResize } from '@websolutespa/bom-core';
2
+
3
+ type IImageHandlerOptions = {
4
+ domains: string[];
5
+ sizes: number[];
6
+ quality: number;
7
+ };
8
+ type IImageOptions = IImageResize & {
9
+ origin: string;
10
+ search: string;
11
+ url: string;
12
+ };
13
+ declare function imageHandler({ domains, sizes, quality, }: IImageHandlerOptions): any;
14
+
15
+ export { type IImageHandlerOptions, type IImageOptions, imageHandler };
package/dist/index.d.ts CHANGED
@@ -12,4 +12,4 @@ type IImageOptions = IImageResize & {
12
12
  };
13
13
  declare function imageHandler({ domains, sizes, quality, }: IImageHandlerOptions): any;
14
14
 
15
- export { IImageHandlerOptions, IImageOptions, imageHandler };
15
+ export { type IImageHandlerOptions, type IImageOptions, imageHandler };
package/dist/index.js CHANGED
@@ -1,44 +1,8 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
33
- imageHandler: () => imageHandler
34
- });
35
- module.exports = __toCommonJS(src_exports);
36
-
37
1
  // src/image/image.handler.ts
38
- var fs = __toESM(require("fs"));
39
- var path = __toESM(require("path"));
40
- var import_sharp = __toESM(require("sharp"));
41
- var import_bom_core = require("@websolutespa/bom-core");
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import sharp from "sharp";
5
+ import { decryptImageResize, ImageStrategy } from "@websolutespa/bom-core";
42
6
 
43
7
  // src/api/api.handler.ts
44
8
  function apiHandler(handler) {
@@ -68,7 +32,7 @@ function errorHandler(error, response) {
68
32
  }
69
33
 
70
34
  // src/image/image.handler.ts
71
- var IMAGE_STRATEGY = process.env.IMAGE_STRATEGY ? process.env.IMAGE_STRATEGY : import_bom_core.ImageStrategy.Mixer;
35
+ var IMAGE_STRATEGY = process.env.IMAGE_STRATEGY ? process.env.IMAGE_STRATEGY : ImageStrategy.Mixer;
72
36
  var IMAGE_MAX_AGE = 604800;
73
37
  var IMAGE_FOCAL_X = 50;
74
38
  var IMAGE_FOCAL_Y = 50;
@@ -84,7 +48,7 @@ function imageHandler({
84
48
  try {
85
49
  let imageOptions;
86
50
  try {
87
- imageOptions = IMAGE_STRATEGY === import_bom_core.ImageStrategy.Token ? getEncryptedImageOptions(request, { domains, sizes, quality }) : getImageOptions(request, { domains, sizes, quality });
51
+ imageOptions = IMAGE_STRATEGY === ImageStrategy.Token ? getEncryptedImageOptions(request, { domains, sizes, quality }) : getImageOptions(request, { domains, sizes, quality });
88
52
  } catch (error) {
89
53
  return response.status(400).json({
90
54
  errors: [{
@@ -100,10 +64,7 @@ function imageHandler({
100
64
  response.setHeader("Cache-Control", `public, max-age=${IMAGE_MAX_AGE}`);
101
65
  return response.send(cachedImage);
102
66
  }
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) {
67
+ if (isInvalidReferer(request)) {
107
68
  return response.status(401).send("you are not authorized to perform this action");
108
69
  }
109
70
  if (imageOptions.url.indexOf("http") === -1 && isVercel()) {
@@ -111,7 +72,9 @@ function imageHandler({
111
72
  }
112
73
  const originalImageBuffer = await getOriginalImage(imageOptions.url, domains, request.headers);
113
74
  if (originalImageBuffer) {
114
- const originalImage = (0, import_sharp.default)(originalImageBuffer);
75
+ const originalImage = sharp(originalImageBuffer, {
76
+ animated: isGIF(imageOptions.url)
77
+ });
115
78
  const resizedImage = await resizeImage(originalImage, imageOptions);
116
79
  const compressedImage = resizedImage.webp({
117
80
  quality: imageOptions.q
@@ -135,6 +98,18 @@ function imageHandler({
135
98
  }
136
99
  });
137
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
+ }
138
113
  function getImageOptions(request, options) {
139
114
  const { slugs, origin = "", search = "", w, h, x, y, q } = request.query;
140
115
  if (!Array.isArray(slugs) || slugs.length === 0) {
@@ -182,10 +157,11 @@ function getEncryptedImageOptions(request, options) {
182
157
  if (typeof t !== "string") {
183
158
  throw "missing t parameter";
184
159
  }
185
- const imageResize = (0, import_bom_core.decryptImageResize)(t);
186
- const url = origin + "/" + slugs.join("/") + search;
160
+ const imageResize = decryptImageResize(t);
161
+ imageResize.src = decodeURIComponent(imageResize.src);
162
+ const url = decodeURIComponent(origin + "/" + slugs.join("/") + search);
187
163
  if (imageResize.src !== url) {
188
- throw "invalid src parameter";
164
+ throw `invalid src parameter ${imageResize.src} ${url}`;
189
165
  }
190
166
  return {
191
167
  ...imageResize,
@@ -200,8 +176,8 @@ async function resizeImage(originalImage, imageOptions) {
200
176
  return originalImage.resize({
201
177
  width: resizeWidth,
202
178
  height: resizeHeight ? resizeHeight : void 0,
203
- fit: import_sharp.default.fit.cover,
204
- position: import_sharp.default.strategy.attention,
179
+ fit: sharp.fit.cover,
180
+ position: sharp.strategy.attention,
205
181
  withoutEnlargement: true
206
182
  });
207
183
  };
@@ -214,10 +190,10 @@ async function resizeImage(originalImage, imageOptions) {
214
190
  const imageToResize = originalImage.clone();
215
191
  const scaledImage = imageToResize.resize(prioritizeHeight ? {
216
192
  height: resizeHeight,
217
- fit: import_sharp.default.fit.cover
193
+ fit: sharp.fit.cover
218
194
  } : {
219
195
  width: resizeWidth,
220
- fit: import_sharp.default.fit.cover
196
+ fit: sharp.fit.cover
221
197
  });
222
198
  const { info: scaledImageInfo } = await scaledImage.toBuffer({ resolveWithObject: true });
223
199
  const extractWidth = resizeWidth ?? scaledImageInfo.width;
@@ -245,10 +221,10 @@ async function resizeImage(originalImage, imageOptions) {
245
221
  return defaultResizeOptions();
246
222
  }
247
223
  }
248
- function getOriginalImage(url, domains, headers, skipUrlValidity = false) {
224
+ function getOriginalImage(url, domains, headers) {
249
225
  return new Promise((resolve, reject) => {
250
226
  if (url.indexOf("http") === 0) {
251
- if (!skipUrlValidity && !checkUrlValidity(url, domains)) {
227
+ if (isInvalidDomain(url, domains)) {
252
228
  return reject({ status: 401, message: "invalid origin" });
253
229
  }
254
230
  fetch(url, {
@@ -311,11 +287,13 @@ function urlToCachedName(options) {
311
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}`);
312
288
  return cachedName;
313
289
  }
314
- function checkUrlValidity(src, domains) {
290
+ function isInvalidDomain(src, domains) {
291
+ if (IMAGE_STRATEGY === ImageStrategy.Token) {
292
+ return false;
293
+ }
315
294
  const url = new URL(src);
316
- return domains.includes(url.hostname);
295
+ return !domains.includes(url.hostname);
317
296
  }
318
- // Annotate the CommonJS export names for ESM import in node:
319
- 0 && (module.exports = {
297
+ export {
320
298
  imageHandler
321
- });
299
+ };
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.1-next.0",
4
4
  "description": "Mixer Image module of the BOM Repository",
5
5
  "keywords": [
6
6
  "bom",
@@ -14,37 +14,39 @@
14
14
  },
15
15
  "scripts": {
16
16
  "lint": "eslint *.ts*",
17
- "test": "jest",
18
- "test-watch": "npm test -- --watch --silent=false",
19
- "coverage:integration": "npm run test -- --coverage",
17
+ "test": "vitest run",
18
+ "test-watch": "vitest",
19
+ "coverage:integration": "npm run test -- --coverage.enabled --coverage.provider=istanbul --coverage.all",
20
20
  "coverage": "run-s -c --silent coverage:*",
21
21
  "compile": "tsup ./src/index.ts --format esm,cjs --dts",
22
22
  "prepack": "bom prepack",
23
- "postpack": "bom postpack"
23
+ "postpack": "bom postpack",
24
+ "types": "tsc --noemit"
24
25
  },
25
26
  "dependencies": {},
26
27
  "peerDependencies": {
27
- "@websolutespa/bom-core": "*",
28
- "next": ">= 14.1.4",
29
- "sharp": ">= 0.30.4"
28
+ "@websolutespa/bom-core": "2.0.1-next.0",
29
+ "next": "15.4.10",
30
+ "sharp": "0.34.2"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@types/sharp": "^0.30.4",
33
- "@websolutespa/bom-cli": "*",
34
- "@websolutespa/test": "*",
35
- "@websolutespa/tsconfig": "*",
36
- "eslint": "^8.56.0",
37
- "eslint-config-websolute": "*",
38
- "npm-run-all": "^4.1.5",
39
- "sharp": "0.30.4",
40
- "ts-node": "^10.9.1",
41
- "tsup": "^6.7.0",
42
- "typescript": "^5.4.5"
34
+ "@websolutespa/bom-cli": "2.0.1-next.0",
35
+ "@websolutespa/test": "2.0.1-next.0",
36
+ "@websolutespa/tsconfig": "2.0.1-next.0",
37
+ "eslint": "9.31.0",
38
+ "@websolutespa/eslint-config": "2.0.1-next.0",
39
+ "npm-run-all": "4.1.5",
40
+ "sharp": "0.34.2",
41
+ "ts-node": "^10.9.2",
42
+ "tsup": "8.5.0",
43
+ "typescript": "5.8.3"
43
44
  },
44
45
  "publishConfig": {
45
46
  "access": "public"
46
47
  },
47
48
  "sideEffects": false,
49
+ "type": "module",
48
50
  "prepack": {
49
51
  "types": "./dist/index.d.ts",
50
52
  "main": "./dist/index.js",
@@ -1,4 +1,4 @@
1
- import '@testing-library/jest-dom';
1
+ import { describe, expect, it } from 'vitest';
2
2
 
3
3
  describe('Example', () => {
4
4
  it('passes', async () => {
@@ -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
  }
@@ -369,7 +365,7 @@ function getCachedImage(pathname: string): Promise<Buffer> {
369
365
  function urlToFileName(url: string): string {
370
366
  // Replacing useless characters with UNDERSCORE
371
367
  const segments = url.split('?');
372
- const path = segments[0];
368
+ const path = segments[0]!;
373
369
  const query = segments[1];
374
370
  let uniqueName = path.replace('://', '_').replace(/\.|\/|\?|=/g, '_');
375
371
  // Replacing last UNDERSCORE with a DOT
@@ -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
  }