node-server-engine 1.2.4 → 1.2.6
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/.env.example +1 -4
- package/README.md +214 -18
- package/dist/entities/Server/Server.js +0 -10
- package/dist/entities/Server/Server.js.map +1 -1
- package/dist/middleware/fileUploader/fileUploader.d.ts +4 -5
- package/dist/middleware/fileUploader/fileUploader.js +68 -255
- package/dist/middleware/fileUploader/fileUploader.js.map +1 -1
- package/dist/middleware/fileUploader/fileUploader.types.d.ts +13 -32
- package/dist/middleware/fileUploader/fileUploader.types.js.map +1 -1
- package/dist/middleware/geminiFileUploader/geminiFileUploader.js +21 -69
- package/dist/middleware/geminiFileUploader/geminiFileUploader.js.map +1 -1
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/multiPartFileUploader/index.d.ts +1 -0
- package/dist/middleware/multiPartFileUploader/index.js +17 -0
- package/dist/middleware/multiPartFileUploader/index.js.map +1 -0
- package/dist/middleware/multiPartFileUploader/multiPartFileUploader.d.ts +3 -0
- package/dist/middleware/multiPartFileUploader/multiPartFileUploader.js +156 -0
- package/dist/middleware/multiPartFileUploader/multiPartFileUploader.js.map +1 -0
- package/dist/utils/createHttpServer/createHttpServer.js.map +1 -1
- package/dist/utils/geminiFileUpload/geminiFileUpload.d.ts +9 -0
- package/dist/utils/geminiFileUpload/geminiFileUpload.js +100 -0
- package/dist/utils/geminiFileUpload/geminiFileUpload.js.map +1 -0
- package/dist/utils/geminiFileUpload/index.d.ts +1 -0
- package/dist/utils/geminiFileUpload/index.js +17 -0
- package/dist/utils/geminiFileUpload/index.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +11 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +3 -1
- package/src/entities/Server/Server.ts +0 -6
- package/src/middleware/fileUploader/fileUploader.ts +70 -270
- package/src/middleware/fileUploader/fileUploader.types.ts +16 -33
- package/src/middleware/geminiFileUploader/geminiFileUploader.ts +19 -68
- package/src/middleware/index.ts +1 -0
- package/src/middleware/multiPartFileUploader/index.ts +1 -0
- package/src/middleware/multiPartFileUploader/multiPartFileUploader.ts +184 -0
- package/src/utils/createHttpServer/createHttpServer.ts +2 -3
- package/src/utils/geminiFileUpload/geminiFileUpload.ts +98 -0
- package/src/utils/geminiFileUpload/index.ts +1 -0
- package/src/utils/index.ts +3 -0
- package/test/env.ts +1 -0
- package/dist/middleware/fileUploader/compressAvatar/compressAvatar.d.ts +0 -6
- package/dist/middleware/fileUploader/compressAvatar/compressAvatar.js +0 -28
- package/dist/middleware/fileUploader/compressAvatar/compressAvatar.js.map +0 -1
- package/dist/middleware/fileUploader/compressAvatar/compressAvatar.types.d.ts +0 -12
- package/dist/middleware/fileUploader/compressAvatar/compressAvatar.types.js +0 -2
- package/dist/middleware/fileUploader/compressAvatar/compressAvatar.types.js.map +0 -1
- package/dist/middleware/fileUploader/compressAvatar/index.d.ts +0 -2
- package/dist/middleware/fileUploader/compressAvatar/index.js +0 -28
- package/dist/middleware/fileUploader/compressAvatar/index.js.map +0 -1
- package/src/middleware/fileUploader/compressAvatar/compressAvatar.ts +0 -25
- package/src/middleware/fileUploader/compressAvatar/compressAvatar.types.ts +0 -12
- package/src/middleware/fileUploader/compressAvatar/index.ts +0 -2
- package/src/middleware/fileUploader/fileUploader.test.ts +0 -310
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import multer from 'multer';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { reportDebug, reportError } from 'utils';
|
|
6
|
+
|
|
7
|
+
const TEMP_DIR: string =
|
|
8
|
+
process.env.TEMP_CHUNK_FOLDER || './uploads/temp_chunks';
|
|
9
|
+
|
|
10
|
+
const namespace = 'engine:middleware:multiPartFileUploader';
|
|
11
|
+
|
|
12
|
+
fs.ensureDirSync(TEMP_DIR);
|
|
13
|
+
|
|
14
|
+
const storage = multer.memoryStorage();
|
|
15
|
+
|
|
16
|
+
async function multiPartFileUploader(
|
|
17
|
+
req: express.Request,
|
|
18
|
+
res: express.Response,
|
|
19
|
+
next: express.NextFunction
|
|
20
|
+
): Promise<void> {
|
|
21
|
+
try {
|
|
22
|
+
const uploadSingle = multer({ storage }).single('file');
|
|
23
|
+
|
|
24
|
+
uploadSingle(req, res, async (err) => {
|
|
25
|
+
if (err) {
|
|
26
|
+
reportError('Error uploading chunk');
|
|
27
|
+
return next(err);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { filename, totalChunks, chunkIndex, uniqueID } = req.body;
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
!filename ||
|
|
34
|
+
!totalChunks ||
|
|
35
|
+
chunkIndex === undefined ||
|
|
36
|
+
!uniqueID ||
|
|
37
|
+
!req.file
|
|
38
|
+
) {
|
|
39
|
+
req.body.uploadDetails = {
|
|
40
|
+
status: 'failed',
|
|
41
|
+
message: 'Missing required fields',
|
|
42
|
+
details: {
|
|
43
|
+
filename,
|
|
44
|
+
totalChunks,
|
|
45
|
+
chunkIndex,
|
|
46
|
+
uniqueID,
|
|
47
|
+
receivedChunk: !!req.file
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
reportDebug({
|
|
51
|
+
namespace,
|
|
52
|
+
message: `Missing required fields`,
|
|
53
|
+
data: {
|
|
54
|
+
status: 'failed',
|
|
55
|
+
details: {
|
|
56
|
+
filename,
|
|
57
|
+
totalChunks,
|
|
58
|
+
chunkIndex,
|
|
59
|
+
uniqueID
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return next();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const sessionFolder = path.join(TEMP_DIR, uniqueID);
|
|
67
|
+
fs.ensureDirSync(sessionFolder);
|
|
68
|
+
|
|
69
|
+
const chunkPath = path.join(
|
|
70
|
+
sessionFolder,
|
|
71
|
+
`${filename}.part${chunkIndex}`
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await fs.writeFile(chunkPath, req.file.buffer);
|
|
76
|
+
} catch (writeErr) {
|
|
77
|
+
reportError(
|
|
78
|
+
`Failed to write chunk ${chunkIndex}: ${(writeErr as Error).message}`
|
|
79
|
+
);
|
|
80
|
+
return next(writeErr);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const uploadedChunks = await fs.readdir(sessionFolder);
|
|
84
|
+
|
|
85
|
+
if (uploadedChunks.length === parseInt(totalChunks, 10)) {
|
|
86
|
+
reportDebug({
|
|
87
|
+
namespace,
|
|
88
|
+
message: `All chunks uploaded. Merging file...`
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
await mergeChunks(filename, totalChunks, sessionFolder);
|
|
93
|
+
} catch (mergeErr) {
|
|
94
|
+
reportError(`File merging failed: ${(mergeErr as Error).message}`);
|
|
95
|
+
return next(mergeErr);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const finalFilePath = path.join(sessionFolder, filename);
|
|
99
|
+
|
|
100
|
+
if (!fs.existsSync(finalFilePath)) {
|
|
101
|
+
reportError('File merging failed: File does not exist');
|
|
102
|
+
return next(new Error('File merging failed'));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
req.body.uploadDetails = {
|
|
106
|
+
status: 'completed',
|
|
107
|
+
message: 'File uploaded and merged successfully',
|
|
108
|
+
details: { filename, uniqueID }
|
|
109
|
+
};
|
|
110
|
+
reportDebug({
|
|
111
|
+
namespace,
|
|
112
|
+
message: `File merged successfully`,
|
|
113
|
+
data: {
|
|
114
|
+
status: 'completed',
|
|
115
|
+
details: { filename, uniqueID }
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return next();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
reportDebug({
|
|
123
|
+
namespace,
|
|
124
|
+
message: `Chunk uploaded successfully`,
|
|
125
|
+
data: {
|
|
126
|
+
filename,
|
|
127
|
+
uniqueID,
|
|
128
|
+
chunkIndex,
|
|
129
|
+
totalChunks
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
req.body.uploadDetails = {
|
|
134
|
+
status: 'pending',
|
|
135
|
+
message: 'Chunk uploaded successfully',
|
|
136
|
+
details: { filename, uniqueID, chunkIndex, totalChunks }
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return next();
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
reportError(
|
|
143
|
+
`Failed to upload or process chunk: ${(error as Error).message}`
|
|
144
|
+
);
|
|
145
|
+
next(error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function mergeChunks(
|
|
150
|
+
filename: string,
|
|
151
|
+
totalChunks: string | number,
|
|
152
|
+
sessionFolder: string
|
|
153
|
+
): Promise<void> {
|
|
154
|
+
const finalFilePath = path.join(sessionFolder, filename);
|
|
155
|
+
const writeStream = fs.createWriteStream(finalFilePath);
|
|
156
|
+
|
|
157
|
+
for (let i = 0; i < parseInt(totalChunks as string, 10); i++) {
|
|
158
|
+
const partPath = path.join(sessionFolder, `${filename}.part${i}`);
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const chunkData = await fs.readFile(partPath);
|
|
162
|
+
writeStream.write(chunkData);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
reportError(`Error reading chunk ${i}: ${(error as Error).message}`);
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
fs.remove(partPath).catch((err: Error) =>
|
|
169
|
+
reportError(`Error removing part ${partPath}: ${err.message}`)
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
writeStream.end();
|
|
174
|
+
|
|
175
|
+
return new Promise<void>((resolve, reject) => {
|
|
176
|
+
writeStream.on('finish', () => resolve(undefined));
|
|
177
|
+
writeStream.on('error', (error) => {
|
|
178
|
+
reportError(`Error merging chunks: ${(error as Error).message}`);
|
|
179
|
+
reject(error);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export { multiPartFileUploader };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import { RequestListener, Server } from 'http';
|
|
3
|
-
import { createServer as createServerHttp2 } from 'http';
|
|
2
|
+
import { createServer, RequestListener, Server } from 'http';
|
|
4
3
|
import {
|
|
5
4
|
createServer as createSecureServer,
|
|
6
5
|
Server as SecureServer
|
|
@@ -30,6 +29,6 @@ export function createHttpServer(
|
|
|
30
29
|
handler
|
|
31
30
|
);
|
|
32
31
|
} else {
|
|
33
|
-
return
|
|
32
|
+
return createServer(handler);
|
|
34
33
|
}
|
|
35
34
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { GoogleAIFileManager } from '@google/generative-ai/server';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import tmp from 'tmp';
|
|
5
|
+
import { reportError, reportDebug } from 'utils/report';
|
|
6
|
+
|
|
7
|
+
const namespace = 'engine:utils:geminiFileUpload';
|
|
8
|
+
|
|
9
|
+
const apiKey = process.env.GOOGLE_AI_KEY;
|
|
10
|
+
if (!apiKey) {
|
|
11
|
+
throw new Error('GOOGLE_AI_KEY is not set in environment variables');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const fileManager = new GoogleAIFileManager(apiKey);
|
|
15
|
+
|
|
16
|
+
export async function geminiFileUpload(
|
|
17
|
+
buffer: Buffer,
|
|
18
|
+
mimeType: string,
|
|
19
|
+
originalName: string
|
|
20
|
+
): Promise<
|
|
21
|
+
| { success: true; originalname: string; fileUri: string; mimeType: string }
|
|
22
|
+
| { success: false; error: unknown }
|
|
23
|
+
> {
|
|
24
|
+
let tempFile;
|
|
25
|
+
try {
|
|
26
|
+
// 1. Create Temp File
|
|
27
|
+
tempFile = tmp.fileSync({ postfix: path.extname(originalName) });
|
|
28
|
+
fs.writeFileSync(tempFile.name, buffer);
|
|
29
|
+
|
|
30
|
+
// 2. Upload File
|
|
31
|
+
const uploadResult = await fileManager.uploadFile(tempFile.name, {
|
|
32
|
+
mimeType,
|
|
33
|
+
displayName: originalName
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (!uploadResult || !uploadResult.file) {
|
|
37
|
+
throw new Error('Upload failed: No file returned');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const file = uploadResult.file;
|
|
41
|
+
reportDebug({
|
|
42
|
+
namespace,
|
|
43
|
+
message: 'Uploaded file successfully',
|
|
44
|
+
data: { displayName: file.displayName, name: file.name }
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
reportDebug({
|
|
48
|
+
namespace,
|
|
49
|
+
message: 'Waiting for file processing...'
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 3. Poll Until File is Processed
|
|
53
|
+
let geminiFile = await fileManager.getFile(file.name);
|
|
54
|
+
while (geminiFile?.state === 'PROCESSING') {
|
|
55
|
+
process.stdout.write('.');
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, 10000));
|
|
57
|
+
geminiFile = await fileManager.getFile(file.name);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!geminiFile || geminiFile.state !== 'ACTIVE') {
|
|
61
|
+
const errorMessage = `File processing failed for ${file.name}`;
|
|
62
|
+
reportError(errorMessage);
|
|
63
|
+
return { success: false, error: new Error(errorMessage) };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
reportDebug({
|
|
67
|
+
namespace,
|
|
68
|
+
message: 'File is ready'
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
originalname: file.name,
|
|
74
|
+
fileUri: file.uri,
|
|
75
|
+
mimeType: file.mimeType
|
|
76
|
+
};
|
|
77
|
+
} catch (error) {
|
|
78
|
+
reportError({
|
|
79
|
+
namespace,
|
|
80
|
+
message: 'Error during Gemini file upload and processing',
|
|
81
|
+
error
|
|
82
|
+
});
|
|
83
|
+
return { success: false, error };
|
|
84
|
+
} finally {
|
|
85
|
+
// Ensure cleanup of temp file
|
|
86
|
+
if (tempFile) {
|
|
87
|
+
try {
|
|
88
|
+
tempFile.removeCallback();
|
|
89
|
+
} catch (cleanupError) {
|
|
90
|
+
reportError({
|
|
91
|
+
namespace,
|
|
92
|
+
message: 'Error cleaning up temp file',
|
|
93
|
+
error: cleanupError
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './geminiFileUpload';
|
package/src/utils/index.ts
CHANGED
package/test/env.ts
CHANGED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.compressAvatar = compressAvatar;
|
|
8
|
-
var _sharp = _interopRequireDefault(require("sharp"));
|
|
9
|
-
/**
|
|
10
|
-
* Compress the user's avatar before uploading
|
|
11
|
-
*/
|
|
12
|
-
function compressAvatar(fileStream, options) {
|
|
13
|
-
const {
|
|
14
|
-
resize: {
|
|
15
|
-
height,
|
|
16
|
-
width
|
|
17
|
-
},
|
|
18
|
-
quality
|
|
19
|
-
} = options;
|
|
20
|
-
const transform = (0, _sharp.default)().resize(width, height, {
|
|
21
|
-
fit: 'cover'
|
|
22
|
-
}).toFormat('jpeg', {
|
|
23
|
-
quality: quality
|
|
24
|
-
});
|
|
25
|
-
fileStream.pipe(transform);
|
|
26
|
-
return fileStream;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=compressAvatar.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compressAvatar.js","names":["_sharp","_interopRequireDefault","require","compressAvatar","fileStream","options","resize","height","width","quality","transform","sharp","fit","toFormat","pipe"],"sources":["../../../../src/middleware/fileUploader/compressAvatar/compressAvatar.ts"],"sourcesContent":["import { Readable } from 'stream';\nimport sharp from 'sharp';\nimport { CompressionOptions } from './compressAvatar.types';\n\n/**\n * Compress the user's avatar before uploading\n */\nexport function compressAvatar(\n fileStream: Readable,\n options: CompressionOptions\n): Readable {\n const {\n resize: { height, width },\n quality\n } = options;\n const transform = sharp()\n .resize(width, height, {\n fit: 'cover'\n })\n .toFormat('jpeg', {\n quality: quality\n });\n fileStream.pipe(transform);\n return fileStream;\n}\n"],"mappings":";;;;;;;AACA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAGA;AACA;AACA;AACO,SAASC,cAAcA,CAC5BC,UAAoB,EACpBC,OAA2B,EACjB;EACV,MAAM;IACJC,MAAM,EAAE;MAAEC,MAAM;MAAEC;IAAM,CAAC;IACzBC;EACF,CAAC,GAAGJ,OAAO;EACX,MAAMK,SAAS,GAAG,IAAAC,cAAK,EAAC,CAAC,CACtBL,MAAM,CAACE,KAAK,EAAED,MAAM,EAAE;IACrBK,GAAG,EAAE;EACP,CAAC,CAAC,CACDC,QAAQ,CAAC,MAAM,EAAE;IAChBJ,OAAO,EAAEA;EACX,CAAC,CAAC;EACJL,UAAU,CAACU,IAAI,CAACJ,SAAS,CAAC;EAC1B,OAAON,UAAU;AACnB","ignoreList":[]}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/** Options to compress image */
|
|
2
|
-
export interface CompressionOptions {
|
|
3
|
-
/** Set dimensions in which the image will be resized */
|
|
4
|
-
resize: {
|
|
5
|
-
/** Height of the resized image */
|
|
6
|
-
height: number;
|
|
7
|
-
/** Width of the resized image */
|
|
8
|
-
width: number;
|
|
9
|
-
};
|
|
10
|
-
/** JPG quality factor to apply when compressing */
|
|
11
|
-
quality: number;
|
|
12
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compressAvatar.types.js","names":[],"sources":["../../../../src/middleware/fileUploader/compressAvatar/compressAvatar.types.ts"],"sourcesContent":["/** Options to compress image */\nexport interface CompressionOptions {\n /** Set dimensions in which the image will be resized */\n resize: {\n /** Height of the resized image */\n height: number;\n /** Width of the resized image */\n width: number;\n };\n /** JPG quality factor to apply when compressing */\n quality: number;\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
var _compressAvatar = require("./compressAvatar");
|
|
7
|
-
Object.keys(_compressAvatar).forEach(function (key) {
|
|
8
|
-
if (key === "default" || key === "__esModule") return;
|
|
9
|
-
if (key in exports && exports[key] === _compressAvatar[key]) return;
|
|
10
|
-
Object.defineProperty(exports, key, {
|
|
11
|
-
enumerable: true,
|
|
12
|
-
get: function () {
|
|
13
|
-
return _compressAvatar[key];
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
var _compressAvatar2 = require("./compressAvatar.types");
|
|
18
|
-
Object.keys(_compressAvatar2).forEach(function (key) {
|
|
19
|
-
if (key === "default" || key === "__esModule") return;
|
|
20
|
-
if (key in exports && exports[key] === _compressAvatar2[key]) return;
|
|
21
|
-
Object.defineProperty(exports, key, {
|
|
22
|
-
enumerable: true,
|
|
23
|
-
get: function () {
|
|
24
|
-
return _compressAvatar2[key];
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_compressAvatar","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_compressAvatar2"],"sources":["../../../../src/middleware/fileUploader/compressAvatar/index.ts"],"sourcesContent":["export * from './compressAvatar';\nexport * from './compressAvatar.types';\n"],"mappings":";;;;;AAAA,IAAAA,eAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,eAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,eAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,eAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,gBAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,gBAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,gBAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,gBAAA,CAAAL,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Readable } from 'stream';
|
|
2
|
-
import sharp from 'sharp';
|
|
3
|
-
import { CompressionOptions } from './compressAvatar.types';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Compress the user's avatar before uploading
|
|
7
|
-
*/
|
|
8
|
-
export function compressAvatar(
|
|
9
|
-
fileStream: Readable,
|
|
10
|
-
options: CompressionOptions
|
|
11
|
-
): Readable {
|
|
12
|
-
const {
|
|
13
|
-
resize: { height, width },
|
|
14
|
-
quality
|
|
15
|
-
} = options;
|
|
16
|
-
const transform = sharp()
|
|
17
|
-
.resize(width, height, {
|
|
18
|
-
fit: 'cover'
|
|
19
|
-
})
|
|
20
|
-
.toFormat('jpeg', {
|
|
21
|
-
quality: quality
|
|
22
|
-
});
|
|
23
|
-
fileStream.pipe(transform);
|
|
24
|
-
return fileStream;
|
|
25
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/** Options to compress image */
|
|
2
|
-
export interface CompressionOptions {
|
|
3
|
-
/** Set dimensions in which the image will be resized */
|
|
4
|
-
resize: {
|
|
5
|
-
/** Height of the resized image */
|
|
6
|
-
height: number;
|
|
7
|
-
/** Width of the resized image */
|
|
8
|
-
width: number;
|
|
9
|
-
};
|
|
10
|
-
/** JPG quality factor to apply when compressing */
|
|
11
|
-
quality: number;
|
|
12
|
-
}
|