@naman_deep_singh/utils 2.4.0 → 2.6.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.
@@ -0,0 +1,415 @@
1
+ /**
2
+ * Compression utilities for data compression/decompression
3
+ * @packageDocumentation
4
+ */
5
+ import { CompressionError } from '../errors/CompressionError.js';
6
+ /**
7
+ * Supported compression algorithms
8
+ */
9
+ export var CompressionAlgorithm;
10
+ (function (CompressionAlgorithm) {
11
+ /** GZIP compression */
12
+ CompressionAlgorithm["GZIP"] = "gzip";
13
+ /** Deflate compression */
14
+ CompressionAlgorithm["DEFLATE"] = "deflate";
15
+ /** Brotli compression (Node.js 10.16.0+) */
16
+ CompressionAlgorithm["BROTLI"] = "brotli";
17
+ })(CompressionAlgorithm || (CompressionAlgorithm = {}));
18
+ /**
19
+ * Main compression utility class
20
+ */
21
+ export class Compression {
22
+ /**
23
+ * Check if compression algorithm is supported
24
+ */
25
+ static isAlgorithmSupported(algorithm) {
26
+ switch (algorithm) {
27
+ case CompressionAlgorithm.GZIP:
28
+ case CompressionAlgorithm.DEFLATE:
29
+ return true;
30
+ case CompressionAlgorithm.BROTLI:
31
+ // Brotli requires Node.js 10.16.0+
32
+ if (typeof process !== 'undefined' && process.versions?.node) {
33
+ const [major, minor, _patch] = process.versions.node
34
+ .split('.')
35
+ .map(Number);
36
+ // Brotli support from Node.js 10.16.0
37
+ return major > 10 || (major === 10 && minor >= 16);
38
+ }
39
+ return false;
40
+ default:
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * Get supported algorithms for current environment
46
+ */
47
+ static getSupportedAlgorithms() {
48
+ const algorithms = [
49
+ CompressionAlgorithm.GZIP,
50
+ CompressionAlgorithm.DEFLATE,
51
+ ];
52
+ if (this.isAlgorithmSupported(CompressionAlgorithm.BROTLI)) {
53
+ algorithms.push(CompressionAlgorithm.BROTLI);
54
+ }
55
+ return algorithms;
56
+ }
57
+ /**
58
+ * Compress data
59
+ * @param input Data to compress (string or Buffer)
60
+ * @param options Compression options
61
+ * @returns Compressed data as Buffer
62
+ */
63
+ static async compress(input, options = {}) {
64
+ const opts = { ...this.DEFAULT_OPTIONS, ...options };
65
+ try {
66
+ this.validateInput(input);
67
+ this.validateOptions(opts);
68
+ const buffer = typeof input === 'string' ? Buffer.from(input, opts.encoding) : input;
69
+ const compressed = await this.compressBuffer(buffer, opts);
70
+ return compressed;
71
+ }
72
+ catch (error) {
73
+ throw this.wrapError(error, 'compress', opts.algorithm, input);
74
+ }
75
+ }
76
+ /**
77
+ * Decompress data
78
+ * @param input Compressed data (Buffer or base64 string)
79
+ * @param options Compression options
80
+ * @returns Decompressed data as Buffer
81
+ */
82
+ static async decompress(input, options = {}) {
83
+ const opts = { ...this.DEFAULT_OPTIONS, ...options };
84
+ try {
85
+ this.validateInput(input);
86
+ const buffer = typeof input === 'string' ? Buffer.from(input, 'base64') : input;
87
+ const decompressed = await this.decompressBuffer(buffer, opts);
88
+ return decompressed;
89
+ }
90
+ catch (error) {
91
+ throw this.wrapError(error, 'decompress', opts.algorithm, input);
92
+ }
93
+ }
94
+ /**
95
+ * Compress data with detailed metrics
96
+ * @param input Data to compress
97
+ * @param options Compression options
98
+ * @returns Compression result with metrics
99
+ */
100
+ static async compressWithMetrics(input, options = {}) {
101
+ const startTime = performance.now();
102
+ const opts = { ...this.DEFAULT_OPTIONS, ...options };
103
+ try {
104
+ this.validateInput(input);
105
+ this.validateOptions(opts);
106
+ const buffer = typeof input === 'string' ? Buffer.from(input, opts.encoding) : input;
107
+ const originalSize = buffer.length;
108
+ const compressed = await this.compressBuffer(buffer, opts);
109
+ const endTime = performance.now();
110
+ const compressedSize = compressed.length;
111
+ const compressionRatio = compressedSize / originalSize;
112
+ return {
113
+ data: opts.encoding === 'base64'
114
+ ? compressed.toString('base64')
115
+ : compressed,
116
+ originalSize,
117
+ compressedSize,
118
+ compressionRatio,
119
+ timeTakenMs: endTime - startTime,
120
+ algorithm: opts.algorithm,
121
+ };
122
+ }
123
+ catch (error) {
124
+ throw this.wrapError(error, 'compressWithMetrics', opts.algorithm, input);
125
+ }
126
+ }
127
+ /**
128
+ * Compress buffer data using specified algorithm
129
+ */
130
+ static async compressBuffer(buffer, options) {
131
+ switch (options.algorithm) {
132
+ case CompressionAlgorithm.GZIP:
133
+ return this.compressGzip(buffer, options.level);
134
+ case CompressionAlgorithm.DEFLATE:
135
+ return this.compressDeflate(buffer, options.level);
136
+ case CompressionAlgorithm.BROTLI:
137
+ return this.compressBrotli(buffer, options.level);
138
+ default:
139
+ throw new CompressionError(`Unsupported algorithm: ${options.algorithm}`, options.algorithm);
140
+ }
141
+ }
142
+ /**
143
+ * Decompress buffer data using specified algorithm
144
+ */
145
+ static async decompressBuffer(buffer, options) {
146
+ switch (options.algorithm) {
147
+ case CompressionAlgorithm.GZIP:
148
+ return this.decompressGzip(buffer);
149
+ case CompressionAlgorithm.DEFLATE:
150
+ return this.decompressDeflate(buffer);
151
+ case CompressionAlgorithm.BROTLI:
152
+ return this.decompressBrotli(buffer);
153
+ default:
154
+ throw new CompressionError(`Unsupported algorithm: ${options.algorithm}`, options.algorithm);
155
+ }
156
+ }
157
+ /**
158
+ * GZIP compression
159
+ */
160
+ static async compressGzip(buffer, level) {
161
+ const { gzip } = await import('zlib');
162
+ return new Promise((resolve, reject) => {
163
+ gzip(buffer, { level }, (error, result) => {
164
+ if (error)
165
+ reject(error);
166
+ else
167
+ resolve(result);
168
+ });
169
+ });
170
+ }
171
+ /**
172
+ * GZIP decompression
173
+ */
174
+ static async decompressGzip(buffer) {
175
+ const { gunzip } = await import('zlib');
176
+ return new Promise((resolve, reject) => {
177
+ gunzip(buffer, (error, result) => {
178
+ if (error)
179
+ reject(error);
180
+ else
181
+ resolve(result);
182
+ });
183
+ });
184
+ }
185
+ /**
186
+ * Deflate compression
187
+ */
188
+ static async compressDeflate(buffer, level) {
189
+ const { deflate } = await import('zlib');
190
+ return new Promise((resolve, reject) => {
191
+ deflate(buffer, { level }, (error, result) => {
192
+ if (error)
193
+ reject(error);
194
+ else
195
+ resolve(result);
196
+ });
197
+ });
198
+ }
199
+ /**
200
+ * Deflate decompression
201
+ */
202
+ static async decompressDeflate(buffer) {
203
+ const { inflate } = await import('zlib');
204
+ return new Promise((resolve, reject) => {
205
+ inflate(buffer, (error, result) => {
206
+ if (error)
207
+ reject(error);
208
+ else
209
+ resolve(result);
210
+ });
211
+ });
212
+ }
213
+ /**
214
+ * Brotli compression (Node.js 10.16.0+)
215
+ */
216
+ static async compressBrotli(buffer, level) {
217
+ const zlib = await import('zlib');
218
+ if (!zlib.brotliCompress) {
219
+ throw new CompressionError('Brotli compression requires Node.js 10.16.0+', CompressionAlgorithm.BROTLI, {
220
+ nodeVersion: process?.version || 'unknown',
221
+ requiredVersion: '>=10.16.0',
222
+ });
223
+ }
224
+ return new Promise((resolve, reject) => {
225
+ zlib.brotliCompress(buffer, {
226
+ params: {
227
+ [zlib.constants.BROTLI_PARAM_QUALITY]: level,
228
+ [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
229
+ },
230
+ }, (error, result) => {
231
+ if (error)
232
+ reject(error);
233
+ else
234
+ resolve(result);
235
+ });
236
+ });
237
+ }
238
+ /**
239
+ * Brotli decompression (Node.js 10.16.0+)
240
+ */
241
+ static async decompressBrotli(buffer) {
242
+ const zlib = await import('zlib');
243
+ if (!zlib.brotliDecompress) {
244
+ throw new CompressionError('Brotli decompression requires Node.js 10.16.0+', CompressionAlgorithm.BROTLI, {
245
+ nodeVersion: process?.version || 'unknown',
246
+ requiredVersion: '>=10.16.0',
247
+ });
248
+ }
249
+ return new Promise((resolve, reject) => {
250
+ zlib.brotliDecompress(buffer, (error, result) => {
251
+ if (error)
252
+ reject(error);
253
+ else
254
+ resolve(result);
255
+ });
256
+ });
257
+ }
258
+ /**
259
+ * Create compression stream
260
+ * @param algorithm Compression algorithm
261
+ * @param options Compression options
262
+ * @returns Compression stream
263
+ */
264
+ static createCompressionStream(algorithm = CompressionAlgorithm.GZIP, options = {}) {
265
+ const opts = { ...this.DEFAULT_OPTIONS, ...options, algorithm };
266
+ this.validateOptions(opts);
267
+ switch (algorithm) {
268
+ case CompressionAlgorithm.GZIP:
269
+ return require('zlib').createGzip({ level: opts.level });
270
+ case CompressionAlgorithm.DEFLATE:
271
+ return require('zlib').createDeflate({ level: opts.level });
272
+ case CompressionAlgorithm.BROTLI:
273
+ const zlib = require('zlib');
274
+ if (!zlib.createBrotliCompress) {
275
+ throw new CompressionError('Brotli stream compression requires Node.js 10.16.0+', CompressionAlgorithm.BROTLI);
276
+ }
277
+ return zlib.createBrotliCompress({
278
+ params: {
279
+ [zlib.constants.BROTLI_PARAM_QUALITY]: opts.level,
280
+ },
281
+ });
282
+ default:
283
+ throw new CompressionError(`Unsupported algorithm for streaming: ${algorithm}`, algorithm);
284
+ }
285
+ }
286
+ /**
287
+ * Create decompression stream
288
+ * @param algorithm Compression algorithm
289
+ * @returns Decompression stream
290
+ */
291
+ static createDecompressionStream(algorithm = CompressionAlgorithm.GZIP) {
292
+ switch (algorithm) {
293
+ case CompressionAlgorithm.GZIP:
294
+ return require('zlib').createGunzip();
295
+ case CompressionAlgorithm.DEFLATE:
296
+ return require('zlib').createInflate();
297
+ case CompressionAlgorithm.BROTLI:
298
+ const zlib = require('zlib');
299
+ if (!zlib.createBrotliDecompress) {
300
+ throw new CompressionError('Brotli stream decompression requires Node.js 10.16.0+', CompressionAlgorithm.BROTLI);
301
+ }
302
+ return zlib.createBrotliDecompress();
303
+ default:
304
+ throw new CompressionError(`Unsupported algorithm for streaming: ${algorithm}`, algorithm);
305
+ }
306
+ }
307
+ /**
308
+ * Stream compression
309
+ * @param readable Readable stream
310
+ * @param writable Writable stream
311
+ * @param options Compression options
312
+ */
313
+ static async compressStream(readable, writable, options = {}) {
314
+ return new Promise((resolve, reject) => {
315
+ const compressor = this.createCompressionStream(options.algorithm, options);
316
+ readable
317
+ .pipe(compressor)
318
+ .pipe(writable)
319
+ .on('finish', resolve)
320
+ .on('error', reject);
321
+ });
322
+ }
323
+ /**
324
+ * Stream decompression
325
+ * @param readable Readable stream
326
+ * @param writable Writable stream
327
+ * @param options Compression options
328
+ */
329
+ static async decompressStream(readable, writable, options = {}) {
330
+ return new Promise((resolve, reject) => {
331
+ const decompressor = this.createDecompressionStream(options.algorithm);
332
+ readable
333
+ .pipe(decompressor)
334
+ .pipe(writable)
335
+ .on('finish', resolve)
336
+ .on('error', reject);
337
+ });
338
+ }
339
+ /**
340
+ * Validate input data
341
+ */
342
+ static validateInput(input) {
343
+ if (input === null || input === undefined) {
344
+ throw new CompressionError('Input cannot be null or undefined');
345
+ }
346
+ if (typeof input !== 'string' && !Buffer.isBuffer(input)) {
347
+ throw new CompressionError(`Input must be string or Buffer, got ${typeof input}`);
348
+ }
349
+ if (typeof input === 'string' && input.length === 0) {
350
+ throw new CompressionError('Input string cannot be empty');
351
+ }
352
+ if (Buffer.isBuffer(input) && input.length === 0) {
353
+ throw new CompressionError('Input buffer cannot be empty');
354
+ }
355
+ }
356
+ /**
357
+ * Validate compression options
358
+ */
359
+ static validateOptions(options) {
360
+ if (!Object.values(CompressionAlgorithm).includes(options.algorithm)) {
361
+ throw new CompressionError(`Invalid algorithm: ${options.algorithm}`, options.algorithm);
362
+ }
363
+ if (options.level < 1 || options.level > 9) {
364
+ throw new CompressionError(`Compression level must be between 1-9, got ${options.level}`, options.algorithm, { level: options.level });
365
+ }
366
+ if (!this.isAlgorithmSupported(options.algorithm)) {
367
+ throw new CompressionError(`Algorithm not supported: ${options.algorithm}`, options.algorithm, {
368
+ supportedAlgorithms: this.getSupportedAlgorithms(),
369
+ nodeVersion: process?.version || 'unknown',
370
+ });
371
+ }
372
+ }
373
+ /**
374
+ * Wrap errors with CompressionError
375
+ */
376
+ static wrapError(error, operation, algorithm, input) {
377
+ if (error instanceof CompressionError) {
378
+ return error;
379
+ }
380
+ const errorMessage = error instanceof Error ? error.message : String(error);
381
+ const inputInfo = Buffer.isBuffer(input)
382
+ ? { size: input.length, type: 'buffer' }
383
+ : { size: input.length, type: 'string' };
384
+ return new CompressionError(`Failed to ${operation} with ${algorithm}: ${errorMessage}`, algorithm, {
385
+ operation,
386
+ input: inputInfo,
387
+ }, error instanceof Error ? error : undefined);
388
+ }
389
+ }
390
+ /**
391
+ * Default compression options
392
+ */
393
+ Compression.DEFAULT_OPTIONS = {
394
+ algorithm: CompressionAlgorithm.GZIP,
395
+ level: 6,
396
+ encoding: 'utf8',
397
+ };
398
+ /**
399
+ * Convenience function for compression
400
+ */
401
+ export async function compress(input, options = {}) {
402
+ return Compression.compress(input, options);
403
+ }
404
+ /**
405
+ * Convenience function for decompression
406
+ */
407
+ export async function decompress(input, options = {}) {
408
+ return Compression.decompress(input, options);
409
+ }
410
+ /**
411
+ * Convenience function for compression with metrics
412
+ */
413
+ export async function compressWithMetrics(input, options = {}) {
414
+ return Compression.compressWithMetrics(input, options);
415
+ }
@@ -1,4 +1,16 @@
1
- // Re-export all utilities
1
+ /**
2
+ * Utils package exports
3
+ * @packageDocumentation
4
+ */
5
+ // Export configuration utilities
2
6
  export { validateConfig, validatePerformanceSettings, mergeConfigs, } from './config.js';
7
+ // Export helper utilities
3
8
  export { isValidArrayIndex, ensurePositiveInteger, safeClone, getPathSegments, hasOwnProperty, } from './helpers.js';
9
+ // Export extension utilities
4
10
  export { defineExtension } from './defineExtension.js';
11
+ // Export timeout utilities
12
+ export { TimeoutManager, withTimeout, } from './timeout.js';
13
+ // Export pool utilities
14
+ export { GenericPool, PoolManager, } from './pool.js';
15
+ // Export compression utilities
16
+ export { Compression, compress, decompress, compressWithMetrics, CompressionAlgorithm, } from './compression.js';