@e-mc/compress 0.9.6 → 0.10.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.
Files changed (4) hide show
  1. package/README.md +10 -14
  2. package/index.d.ts +4 -4
  3. package/index.js +182 -163
  4. package/package.json +3 -4
package/README.md CHANGED
@@ -9,13 +9,11 @@
9
9
 
10
10
  ## Interface
11
11
 
12
- * [View Source](https://www.unpkg.com/@e-mc/types@0.9.6/lib/index.d.ts)
12
+ * [View Source](https://www.unpkg.com/@e-mc/types@0.10.0/lib/index.d.ts)
13
13
 
14
14
  ```typescript
15
- import type { CompressLevel } from "./squared";
16
-
17
15
  import type { IModule, ModuleConstructor } from "./index";
18
- import type { BufferResult, CompressFormat, TryFileCompressor } from "./compress";
16
+ import type { BufferResult, CompressFormat, CompressLevel, ReadableOptions, TryFileCompressor } from "./compress";
19
17
  import type { CompressModule, CompressSettings } from "./settings";
20
18
 
21
19
  import type { WriteStream } from "fs";
@@ -30,7 +28,7 @@ interface ICompress extends IModule {
30
28
  init(...args: unknown[]): this;
31
29
  register(format: string, callback: TryFileCompressor): void;
32
30
  getLevel(value: string, fallback?: number): number | undefined;
33
- getReadable(file: string | URL | Buffer): Readable;
31
+ getReadable(file: string | URL | Buffer, options?: ReadableOptions): Readable;
34
32
  createGzip(file: string | Buffer, options?: CompressLevel): Gzip;
35
33
  createBrotliCompress(file: string | Buffer, options?: CompressLevel): BrotliCompress;
36
34
  createWriteStreamAsGzip(file: string | Buffer, output: string, options?: CompressLevel): WriteStream;
@@ -41,6 +39,8 @@ interface ICompress extends IModule {
41
39
  tryFile(file: string | Buffer, output: string, options?: CompressFormat): Promise<BufferResult>;
42
40
  tryImage(file: string, options: CompressFormat): Promise<BufferResult>;
43
41
  tryImage(file: string | Buffer, output: string, options?: CompressFormat): Promise<BufferResult>;
42
+ set chunkSize(value: number | string | undefined): void;
43
+ get chunkSize(): number | undefined;
44
44
  get settings(): CompressSettings;
45
45
  }
46
46
 
@@ -61,10 +61,6 @@ interface CompressModule {
61
61
  gzip?: ZlibOptions;
62
62
  brotli?: BrotliOptions;
63
63
  zopfli?: ZopfliOptions;
64
- tinify?: {
65
- api_key?: string;
66
- proxy?: string;
67
- };
68
64
  settings?: {
69
65
  broadcast_id?: string | string[];
70
66
  cache?: boolean;
@@ -104,8 +100,8 @@ stream
104
100
  .on("error", err => console.error(err));
105
101
 
106
102
  const options = {
107
- plugin: "tinify",
108
- format: "png", // Optional with extension
103
+ plugin: "@pi-r/tinify",
104
+ format: "png", // Recommended
109
105
  timeout: 60 * 1000, // 1m
110
106
  options: {
111
107
  apiKey: "**********" // Override settings
@@ -120,9 +116,9 @@ instance.tryImage("/tmp/image.png", "/path/output/compressed.png", options)
120
116
 
121
117
  ## References
122
118
 
123
- - https://www.unpkg.com/@e-mc/types@0.9.6/lib/squared.d.ts
124
- - https://www.unpkg.com/@e-mc/types@0.9.6/lib/compress.d.ts
125
- - https://www.unpkg.com/@e-mc/types@0.9.6/lib/settings.d.ts
119
+ - https://www.unpkg.com/@e-mc/types@0.10.0/lib/squared.d.ts
120
+ - https://www.unpkg.com/@e-mc/types@0.10.0/lib/compress.d.ts
121
+ - https://www.unpkg.com/@e-mc/types@0.10.0/lib/settings.d.ts
126
122
 
127
123
  * https://www.npmjs.com/package/@types/node
128
124
 
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { CompressConstructor } from '../types/lib';
2
-
3
- declare const Compress: CompressConstructor;
4
-
1
+ import type { CompressConstructor } from '../types/lib';
2
+
3
+ declare const Compress: CompressConstructor;
4
+
5
5
  export = Compress;
package/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
+ var _a;
2
3
  const path = require("path");
3
4
  const fs = require("fs");
4
5
  const stream = require("stream");
5
6
  const zlib = require("zlib");
6
7
  const wawoff2 = require("wawoff2");
7
- const tinify = require("tinify");
8
- const { toSfnt, toWoff } = require('woff2sfnt-sfnt2woff');
9
- const types_1 = require("@e-mc/types");
10
8
  const module_1 = require("@e-mc/module");
9
+ const types_1 = require("@e-mc/types");
10
+ const { toSfnt, toWoff } = require('woff2sfnt-sfnt2woff');
11
+ const kChunkSize = Symbol('chunkSize');
11
12
  const CACHE_IMAGE = {};
12
13
  const CACHE_FONT = {};
13
14
  const CACHE_FONTFROM = {};
@@ -20,15 +21,15 @@ const GZIP_ZOPFLI = (function () {
20
21
  return require('node-zopfli');
21
22
  }
22
23
  catch {
24
+ return null;
23
25
  }
24
- return null;
25
26
  })();
26
- function setCacheData(index) {
27
+ function setCacheData(instance, index) {
27
28
  if (CACHE_INIT[index]) {
28
29
  return true;
29
30
  }
30
- TEMP_DIR || (TEMP_DIR = this.getTempDir({ moduleDir: true, createDir: true, increment: 5 }));
31
- const settings = this.settings;
31
+ TEMP_DIR || (TEMP_DIR = instance.getTempDir({ moduleDir: true, createDir: true, increment: 5 }));
32
+ const settings = instance.settings;
32
33
  const expires = (0, types_1.parseExpires)(settings.cache_expires || 0);
33
34
  if (TEMP_DIR) {
34
35
  if (expires === 0) {
@@ -43,7 +44,7 @@ function setCacheData(index) {
43
44
  const srcDir = path.join(TEMP_DIR, ...paths);
44
45
  try {
45
46
  fs.readdirSync(srcDir, { withFileTypes: true }).forEach(item => {
46
- var _a, _b, _c;
47
+ var _b, _c, _d;
47
48
  const filename = item.name;
48
49
  if (item.isFile()) {
49
50
  const pathname = path.join(srcDir, filename);
@@ -57,7 +58,7 @@ function setCacheData(index) {
57
58
  CACHE_FONTTO[filename] = paths[1];
58
59
  }
59
60
  else {
60
- ((_b = (CACHE_IMAGE[_a = paths[0]] || (CACHE_IMAGE[_a] = {})))[_c = paths[1]] || (_b[_c] = {}))[filename] = stat.ctime;
61
+ ((_c = (CACHE_IMAGE[_b = paths[0]] || (CACHE_IMAGE[_b] = {})))[_d = paths[1]] || (_c[_d] = {}))[filename] = stat.ctime;
61
62
  }
62
63
  return;
63
64
  }
@@ -79,13 +80,23 @@ function setCacheData(index) {
79
80
  }
80
81
  return CACHE_INIT[index] = true;
81
82
  }
83
+ function getOutputSize(startLength, data) {
84
+ if (startLength === 0 || !data) {
85
+ return '';
86
+ }
87
+ const offset = Buffer.byteLength(data) - startLength;
88
+ return ` (${(offset > 0 ? '+' : '') + (0, types_1.formatSize)(offset)})`;
89
+ }
90
+ const sanitizePath = (value) => value.replace(/[\\/]/g, '_');
82
91
  class Compress extends module_1 {
83
92
  static singleton() {
84
93
  if (!SINGLETON_INSTANCE) {
85
94
  SINGLETON_INSTANCE = new Compress();
86
95
  Object.defineProperty(SINGLETON_INSTANCE, "_logEnabled", { value: false, enumerable: true, writable: false });
87
96
  Object.defineProperty(SINGLETON_INSTANCE, "_logFlushed", { value: true, enumerable: true, writable: false });
88
- Object.defineProperty(SINGLETON_INSTANCE, "host", { set(value) { }, get() { return null; } });
97
+ Object.defineProperty(SINGLETON_INSTANCE, "host", { set(value) { }, get() {
98
+ return null;
99
+ } });
89
100
  }
90
101
  return SINGLETON_INSTANCE;
91
102
  }
@@ -99,6 +110,7 @@ class Compress extends module_1 {
99
110
  };
100
111
  this.compressors = {};
101
112
  this._moduleName = 'compress';
113
+ this[_a] = undefined;
102
114
  }
103
115
  init(...args) {
104
116
  let { gzip_level, brotli_quality, zopfli_iterations, chunk_size } = (0, types_1.isPlainObject)(args[0]) && args[0].settings || this.settings;
@@ -111,7 +123,7 @@ class Compress extends module_1 {
111
123
  if (zopfli_iterations && (zopfli_iterations = Math.floor(+zopfli_iterations)) > 0) {
112
124
  this.level.zopfli = zopfli_iterations;
113
125
  }
114
- if (chunk_size && ((0, types_1.isString)(chunk_size) && (0, types_1.alignSize)(chunk_size = (0, types_1.formatSize)(chunk_size), 1) || (0, types_1.alignSize)(chunk_size = +chunk_size, 1))) {
126
+ if (chunk_size !== undefined) {
115
127
  this.chunkSize = chunk_size;
116
128
  }
117
129
  return this;
@@ -137,8 +149,23 @@ class Compress extends module_1 {
137
149
  return zlib.constants.BROTLI_DEFAULT_QUALITY;
138
150
  }
139
151
  }
140
- getReadable(file) {
141
- return file instanceof Buffer ? stream.Readable.from(file) : fs.createReadStream(file);
152
+ getReadable(file, options) {
153
+ if (file instanceof Buffer) {
154
+ return stream.Readable.from(file);
155
+ }
156
+ try {
157
+ if (!options?.throwsPermission || this.canRead(file, { ownPermissionOnly: true })) {
158
+ return fs.createReadStream(file);
159
+ }
160
+ options = undefined;
161
+ throw (0, types_1.errorValue)("Operation not permitted", file.toString());
162
+ }
163
+ catch (err) {
164
+ if (!options || options.throwsPermission && module_1.isErrorCode(err, 'EACCES') || options.throwsDoesNotExist && module_1.isErrorCode(err, 'ENOENT')) {
165
+ throw err;
166
+ }
167
+ }
168
+ return stream.Readable.from(Buffer.alloc(0));
142
169
  }
143
170
  createGzip(file, options) {
144
171
  let algorithm, level, chunkSize;
@@ -154,7 +181,7 @@ class Compress extends module_1 {
154
181
  else {
155
182
  zopfli.numiterations ?? (zopfli.numiterations = this.level.zopfli);
156
183
  }
157
- return this.getReadable(file).pipe(GZIP_ZOPFLI.createGzip(zopfli));
184
+ return this.getReadable(file, options).pipe(GZIP_ZOPFLI.createGzip(zopfli));
158
185
  }
159
186
  level = undefined;
160
187
  }
@@ -172,7 +199,7 @@ class Compress extends module_1 {
172
199
  else {
173
200
  gzip.chunkSize ?? (gzip.chunkSize = this.chunkSize);
174
201
  }
175
- return this.getReadable(file).pipe(zlib.createGzip(gzip));
202
+ return this.getReadable(file, options).pipe(zlib.createGzip(gzip));
176
203
  }
177
204
  createBrotliCompress(file, options) {
178
205
  let level, chunkSize, mimeType;
@@ -199,7 +226,7 @@ class Compress extends module_1 {
199
226
  else {
200
227
  brotli.chunkSize ?? (brotli.chunkSize = this.chunkSize);
201
228
  }
202
- return this.getReadable(file).pipe(zlib.createBrotliCompress(brotli));
229
+ return this.getReadable(file, options).pipe(zlib.createBrotliCompress(brotli));
203
230
  }
204
231
  createWriteStreamAsGzip(file, output, options) {
205
232
  return this.createGzip(file, options).pipe(fs.createWriteStream(output));
@@ -226,21 +253,18 @@ class Compress extends module_1 {
226
253
  options = output;
227
254
  output = '';
228
255
  }
229
- else {
230
- options || (options = {});
231
- }
232
256
  if (!(0, types_1.isString)(output)) {
233
257
  output = typeof file === 'string' ? file : '';
234
258
  }
259
+ options || (options = {});
235
260
  const { filename, startTime = process.hrtime(), timeout = 0, sessionId, broadcastId } = options;
236
- let format = options.format;
261
+ let format = options.format, hash = options.etag;
237
262
  if (!format) {
238
263
  return Promise.reject((0, types_1.errorValue)("Missing option \"format\"", output || filename));
239
264
  }
240
- let hash = options.etag;
241
265
  const cache = this.settings.cache ? !!(hash && (hash = module_1.asHash(hash)) || Buffer.isBuffer(file) && (hash = module_1.asHash(file))) : false;
242
266
  return new Promise((resolve, reject) => {
243
- let timer = null, aborted;
267
+ let timer = null, startLength = 0, aborted;
244
268
  const endProcess = (err, data = null, ext, result, fromCache) => {
245
269
  if (timer) {
246
270
  clearTimeout(timer);
@@ -250,7 +274,8 @@ class Compress extends module_1 {
250
274
  return;
251
275
  }
252
276
  if (!fromCache) {
253
- this.writeTimeProcess(ext || format, (0, types_1.isString)(result) ? path.basename(result) : filename || "Completed", startTime, { type: 8, sessionId, broadcastId });
277
+ const status = (0, types_1.isString)(result) ? path.basename(result) : filename || "Completed";
278
+ this.writeTimeProcess(ext || format, status + getOutputSize(startLength, data), startTime, { type: 8, sessionId, broadcastId });
254
279
  }
255
280
  if (result) {
256
281
  options.outFile = result;
@@ -304,7 +329,7 @@ class Compress extends module_1 {
304
329
  };
305
330
  const hasFont = () => {
306
331
  let from, to;
307
- if (cache && (CACHE_INIT[0] || setCacheData.call(this, 0)) && (from = CACHE_FONTFROM[hash]) && (to = CACHE_FONTTO[hash])) {
332
+ if (cache && (CACHE_INIT[0] || setCacheData(this, 0)) && (from = CACHE_FONTFROM[hash]) && (to = CACHE_FONTTO[hash])) {
308
333
  const cacheKey = from + `_${to}_` + hash;
309
334
  const tempFont = CACHE_FONT[cacheKey];
310
335
  if (tempFont) {
@@ -330,8 +355,11 @@ class Compress extends module_1 {
330
355
  return false;
331
356
  }
332
357
  };
333
- const errorResponse = (font) => endProcess((0, types_1.errorValue)("Unsupported MIME", (font ? font.mime : "Unknown") + ': ' + (output || filename || "Unknown")));
358
+ const errorResponse = (font) => {
359
+ endProcess((0, types_1.errorValue)("Unsupported MIME", (font?.mime || "Unknown") + ': ' + (output || filename || "Unknown")));
360
+ };
334
361
  const data = Buffer.isBuffer(file) ? file : fs.readFileSync(file);
362
+ startLength = Buffer.byteLength(data);
335
363
  switch (format = format.toLowerCase()) {
336
364
  case 'gz':
337
365
  case 'br': {
@@ -342,7 +370,10 @@ class Compress extends module_1 {
342
370
  }
343
371
  else {
344
372
  chunks = [];
345
- transform = this[format === 'gz' ? 'createGzip' : 'createBrotliCompress'](data, options).on('data', chunk => chunks.push(chunk));
373
+ transform = this[format === 'gz' ? 'createGzip' : 'createBrotliCompress'](data, options);
374
+ transform.on('data', chunk => {
375
+ chunks.push(chunk);
376
+ });
346
377
  }
347
378
  transform
348
379
  .on('finish', () => {
@@ -363,7 +394,7 @@ class Compress extends module_1 {
363
394
  }
364
395
  startProcess(false);
365
396
  const checkResult = (result, from) => {
366
- module_1.resolveMime(result).then(font => {
397
+ void module_1.resolveMime(result).then(font => {
367
398
  switch (font?.mime) {
368
399
  case "font/ttf":
369
400
  case "font/otf":
@@ -375,7 +406,7 @@ class Compress extends module_1 {
375
406
  }
376
407
  });
377
408
  };
378
- module_1.resolveMime(data)
409
+ void module_1.resolveMime(data)
379
410
  .then(font => {
380
411
  switch (font?.mime) {
381
412
  case "font/woff":
@@ -388,16 +419,16 @@ class Compress extends module_1 {
388
419
  if (cache) {
389
420
  CACHE_FONTFROM[hash] = 'woff2';
390
421
  }
391
- wawoff2.decompress(data).then(woff => checkResult(woff, 'woff2'));
422
+ void wawoff2.decompress(data).then(woff => {
423
+ checkResult(woff, 'woff2');
424
+ });
392
425
  break;
393
426
  default:
394
427
  errorResponse(font);
395
428
  break;
396
429
  }
397
430
  })
398
- .catch((err) => {
399
- endProcess(err);
400
- });
431
+ .catch(endProcess);
401
432
  break;
402
433
  }
403
434
  case 'woff':
@@ -406,7 +437,7 @@ class Compress extends module_1 {
406
437
  return;
407
438
  }
408
439
  const checkResult = (result, mimeType, from) => {
409
- module_1.resolveMime(result).then(font => {
440
+ void module_1.resolveMime(result).then(font => {
410
441
  if (font?.mime === mimeType) {
411
442
  writeFont(result, font.ext, from);
412
443
  }
@@ -416,14 +447,16 @@ class Compress extends module_1 {
416
447
  });
417
448
  };
418
449
  startProcess(true);
419
- module_1.resolveMime(data)
450
+ void module_1.resolveMime(data)
420
451
  .then(font => {
421
452
  switch (font?.mime) {
422
453
  case "font/ttf":
423
454
  if (cache) {
424
455
  CACHE_FONTFROM[hash] = 'ttf';
425
456
  }
426
- wawoff2.compress(data).then(result => checkResult(result, "font/woff2", 'ttf'));
457
+ void wawoff2.compress(data).then(result => {
458
+ checkResult(result, "font/woff2", 'ttf');
459
+ });
427
460
  break;
428
461
  case "font/otf":
429
462
  if (cache) {
@@ -436,33 +469,29 @@ class Compress extends module_1 {
436
469
  break;
437
470
  }
438
471
  })
439
- .catch((err) => {
440
- endProcess(err);
441
- });
472
+ .catch(endProcess);
442
473
  break;
443
474
  }
444
475
  default: {
445
476
  const compressor = this.compressors[format]?.bind(this);
446
- if (typeof compressor === 'function') {
447
- startProcess(true);
448
- if (compressor.toString().startsWith('async')) {
449
- compressor.call(this, file, output, options)
450
- .then(result => {
451
- if (typeof result === 'string') {
452
- endProcess(null, null, format, result);
453
- }
454
- else {
455
- endProcess(null, result, format);
456
- }
457
- })
458
- .catch((err) => endProcess(err));
459
- }
460
- else {
461
- compressor.call(this, file, output, options, endProcess);
462
- }
477
+ if (typeof compressor !== 'function') {
478
+ throw (0, types_1.errorValue)("Missing compression plugin", format);
479
+ }
480
+ startProcess(true);
481
+ if (compressor.toString().startsWith('async')) {
482
+ compressor.call(this, file, output, options)
483
+ .then(result => {
484
+ if (typeof result === 'string') {
485
+ endProcess(null, null, format, result);
486
+ }
487
+ else {
488
+ endProcess(null, result, format);
489
+ }
490
+ })
491
+ .catch(endProcess);
463
492
  }
464
493
  else {
465
- throw (0, types_1.errorValue)("Missing compression plugin", format);
494
+ void compressor.call(this, file, output, options, endProcess);
466
495
  }
467
496
  break;
468
497
  }
@@ -481,14 +510,42 @@ class Compress extends module_1 {
481
510
  else {
482
511
  options || (options = {});
483
512
  }
484
- const { plugin = "tinify", filename, startTime = process.hrtime(), timeout = 0, proxyUrl, sessionId, broadcastId } = options;
513
+ const { filename, startTime = process.hrtime(), timeout = 0, sessionId, broadcastId } = options;
514
+ let plugin = options.plugin;
515
+ if ((0, types_1.isString)(plugin)) {
516
+ if (types_1.IMPORT_MAP[plugin]) {
517
+ plugin = types_1.IMPORT_MAP[plugin];
518
+ }
519
+ }
520
+ else {
521
+ return Promise.reject();
522
+ }
485
523
  if (!(0, types_1.isString)(output)) {
486
524
  output = typeof file === 'string' ? file : '';
487
525
  }
488
526
  const ext = output ? path.extname(output).substring(1) : options.format || "Unknown";
489
- const format = options.format || ext;
490
- return new Promise((resolve, reject) => {
491
- let timer = null, hash, cacheKey, aborted, apiKey;
527
+ const getFormat = () => output ? path.basename(output) : ext;
528
+ let data;
529
+ if (Buffer.isBuffer(file)) {
530
+ data = file;
531
+ }
532
+ else {
533
+ try {
534
+ data = fs.readFileSync(file);
535
+ }
536
+ catch (err) {
537
+ return Promise.reject(err);
538
+ }
539
+ }
540
+ if (!options.mimeType) {
541
+ const out = await module_1.resolveMime(data);
542
+ if (out) {
543
+ options.mimeType = out.mime;
544
+ }
545
+ }
546
+ const startLength = Buffer.byteLength(data);
547
+ return new Promise(async (resolve, reject) => {
548
+ let timer = null, hash, cacheKey, aborted;
492
549
  const failed = (err) => {
493
550
  aborted = true;
494
551
  if (timer) {
@@ -496,6 +553,32 @@ class Compress extends module_1 {
496
553
  }
497
554
  reject(err);
498
555
  };
556
+ const complete = (err, result, ctime) => {
557
+ if (err) {
558
+ reject(err);
559
+ return;
560
+ }
561
+ const value = output ? path.basename(output) : filename || (0, types_1.isString)(file) && path.basename(file);
562
+ const status = value ? plugin + ': ' + value : "Completed";
563
+ if (ctime) {
564
+ this.formatMessage(8, value ? path.extname(value).substring(1) : '', [status, 'cache'], ctime.toLocaleString(), { ...module_1.LOG_STYLE_NOTICE, hintBold: true, sessionId, broadcastId });
565
+ }
566
+ else {
567
+ this.writeTimeProcess(ext, status + getOutputSize(startLength, result), startTime, { type: 8, sessionId, broadcastId });
568
+ }
569
+ if (!ctime && hash && cacheKey && TEMP_DIR) {
570
+ const pathname = path.join(TEMP_DIR, sanitizePath(plugin), hash);
571
+ if (module_1.createDir(pathname)) {
572
+ fs.writeFile(path.join(pathname, cacheKey), result, error => {
573
+ var _b, _c;
574
+ if (!error) {
575
+ ((_b = (CACHE_IMAGE[plugin] || (CACHE_IMAGE[plugin] = {})))[_c = hash] || (_b[_c] = {}))[cacheKey] = new Date();
576
+ }
577
+ });
578
+ }
579
+ }
580
+ resolve(result);
581
+ };
499
582
  const success = (result, ctime) => {
500
583
  if (aborted) {
501
584
  return;
@@ -503,137 +586,73 @@ class Compress extends module_1 {
503
586
  if (timer) {
504
587
  clearTimeout(timer);
505
588
  }
506
- const complete = (err) => {
507
- if (err) {
508
- reject(err);
509
- return;
510
- }
511
- const value = output ? path.basename(output) : filename || (0, types_1.isString)(file) && path.basename(file);
512
- const status = value ? plugin + ' -> ' + value : "Completed";
513
- if (ctime) {
514
- this.formatMessage(8, value ? path.extname(value).substring(1) : '', [status, 'cache'], ctime.toLocaleString(), { ...module_1.LOG_STYLE_NOTICE, hintBold: true, sessionId, broadcastId });
515
- }
516
- else {
517
- this.writeTimeProcess(ext, status, startTime, { type: 8, sessionId, broadcastId });
518
- }
519
- if (!ctime && hash && cacheKey && TEMP_DIR) {
520
- const pathname = path.join(TEMP_DIR, plugin, hash);
521
- if (module_1.createDir(pathname)) {
522
- fs.writeFile(path.join(pathname, cacheKey), result, error => {
523
- var _a, _b;
524
- if (!error) {
525
- ((_a = (CACHE_IMAGE[plugin] || (CACHE_IMAGE[plugin] = {})))[_b = hash] || (_a[_b] = {}))[cacheKey] = new Date();
526
- }
527
- });
528
- }
529
- }
530
- resolve(result);
531
- };
532
589
  if (output) {
533
- fs.writeFile(output, result, err => complete(err));
590
+ fs.writeFile(output, result, err => {
591
+ complete(err, result, ctime);
592
+ });
534
593
  }
535
594
  else {
536
- complete(null);
595
+ complete(null, result, ctime);
537
596
  }
538
597
  };
539
- const getFormat = () => output ? path.basename(output) : ext;
540
- if (plugin === "tinify") {
541
- switch (format) {
542
- case 'png':
543
- case 'jpg':
544
- case 'jpeg':
545
- case 'webp':
546
- apiKey = options.options?.apiKey || (module_1.enabled("process.env.apply") ? process.env.TINIFY_KEY : '');
547
- break;
548
- default:
549
- failed((0, types_1.errorMessage)(plugin, "Unsupported MIME", format));
550
- return;
551
- }
552
- if (!apiKey) {
553
- failed((0, types_1.errorMessage)(plugin, 'Missing API key'));
554
- return;
555
- }
556
- switch (module_1.lookupMime(ext)) {
557
- case "image/jpeg":
558
- case "image/png":
559
- case "image/webp":
560
- break;
561
- default:
562
- failed((0, types_1.errorMessage)(plugin, "Unsupported MIME", getFormat()));
563
- return;
564
- }
565
- }
566
- let data;
567
- try {
568
- data = Buffer.isBuffer(file) ? file : fs.readFileSync(file);
569
- }
570
- catch (err) {
571
- failed(err);
572
- return;
573
- }
574
- if (this.settings.cache && setCacheData.call(this, 1)) {
598
+ if (this.settings.cache && setCacheData(this, 1)) {
575
599
  let stored;
576
600
  try {
577
- stored = (CACHE_IMAGE[plugin] || (CACHE_IMAGE[plugin] = {}))[hash = module_1.asHash(data)];
578
- cacheKey = plugin + ':' + module_1.asHash(apiKey ? format + apiKey : module_1.asString(options.options), 'md5');
601
+ hash = module_1.asHash(data);
602
+ stored = (CACHE_IMAGE[plugin] || (CACHE_IMAGE[plugin] = {}))[hash];
603
+ cacheKey = plugin + ((0, types_1.isPlainObject)(options.options) ? ':' + module_1.asHash(module_1.asString(options.options), 'md5') : '');
579
604
  const ctime = stored?.[cacheKey];
580
605
  if (ctime) {
581
- success(fs.readFileSync(path.join(TEMP_DIR, plugin, hash, cacheKey)), ctime);
606
+ success(fs.readFileSync(path.join(TEMP_DIR, sanitizePath(plugin), hash, cacheKey)), ctime);
582
607
  return;
583
608
  }
584
609
  }
585
610
  catch {
611
+ hash = undefined;
586
612
  if (stored && cacheKey) {
587
613
  delete stored[cacheKey];
588
614
  }
589
615
  }
590
616
  }
591
617
  this.formatMessage(8, ext, ['Compressing image...', plugin], filename || output, { titleColor: 'magenta', sessionId, broadcastId });
592
- if (timeout > 0) {
593
- timer = setTimeout(() => failed((0, types_1.errorMessage)(plugin, "Timeout was exceeded")), timeout);
594
- }
595
- if (apiKey) {
596
- const apiProxy = proxyUrl && (typeof proxyUrl === 'function' ? proxyUrl("https://api.tinify.com") : proxyUrl) || this.module.tinify?.proxy || module_1.enabled("process.env.apply") && process.env.TINIFY_PROXY || '';
597
- tinify.key = apiKey;
598
- tinify.proxy = apiProxy;
599
- tinify.validate(err => {
600
- if (!err) {
601
- tinify.fromBuffer(data).toBuffer((error, result) => {
602
- if (!error && result) {
603
- success(result);
604
- }
605
- else {
606
- failed(error || new Error("Unknown"));
607
- }
608
- });
618
+ try {
619
+ let transform;
620
+ try {
621
+ transform = require(plugin);
622
+ }
623
+ catch {
624
+ transform = await (0, types_1.importESM)(plugin, true);
625
+ }
626
+ const out = transform.call(this, options.options, options.mimeType);
627
+ if (timeout > 0) {
628
+ timer = setTimeout(() => {
629
+ failed((0, types_1.errorMessage)(plugin, "Timeout was exceeded"));
630
+ }, timeout);
631
+ }
632
+ void out(data).then(result => {
633
+ if (result !== data) {
634
+ success(result);
609
635
  }
610
636
  else {
611
- failed(err);
637
+ failed((0, types_1.errorMessage)(plugin, "Unsupported MIME", getFormat()));
612
638
  }
613
639
  });
614
640
  }
615
- else {
616
- try {
617
- const transform = require(plugin);
618
- transform(options.options)(data).then(result => {
619
- if (result !== data) {
620
- success(result);
621
- }
622
- else {
623
- failed((0, types_1.errorMessage)(plugin, "Unsupported MIME", getFormat()));
624
- }
625
- });
626
- }
627
- catch (err) {
628
- failed(err);
629
- }
641
+ catch (err) {
642
+ failed(err);
630
643
  }
631
644
  });
632
645
  }
646
+ set chunkSize(value) {
647
+ this[kChunkSize] = !isNaN(value = (0, types_1.alignSize)(value, 1)) ? value : NaN;
648
+ }
649
+ get chunkSize() {
650
+ return this[kChunkSize];
651
+ }
633
652
  get settings() {
634
- var _a;
635
- return (_a = this.module).settings || (_a.settings = {});
653
+ var _b;
654
+ return (_b = this.module).settings || (_b.settings = {});
636
655
  }
637
656
  }
638
-
657
+ _a = kChunkSize;
639
658
  module.exports = Compress;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e-mc/compress",
3
- "version": "0.9.6",
3
+ "version": "0.10.0",
4
4
  "description": "Compress constructor for E-mc.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -23,9 +23,8 @@
23
23
  "license": "BSD 3-Clause",
24
24
  "homepage": "https://github.com/anpham6/e-mc#readme",
25
25
  "dependencies": {
26
- "@e-mc/module": "0.9.6",
27
- "@e-mc/types": "0.9.6",
28
- "tinify": "^1.7.1",
26
+ "@e-mc/module": "0.10.0",
27
+ "@e-mc/types": "0.10.0",
29
28
  "wawoff2": "^2.0.1",
30
29
  "woff2sfnt-sfnt2woff": "^1.0.0"
31
30
  }