
- Complete NestJS TypeScript implementation with WebSocket support - Direct messaging (DM) and group chat functionality - End-to-end encryption with AES encryption and key pairs - Media file support (images, videos, audio, documents) up to 100MB - Push notifications with Firebase Cloud Messaging integration - Mention alerts and real-time typing indicators - User authentication with JWT and Passport - SQLite database with TypeORM entities and relationships - Comprehensive API documentation with Swagger/OpenAPI - File upload handling with secure access control - Online/offline status tracking and presence management - Message editing, deletion, and reply functionality - Notification management with automatic cleanup - Health check endpoint for monitoring - CORS configuration for cross-origin requests - Environment-based configuration management - Structured for Flutter SDK integration Features implemented: ✅ Real-time messaging with Socket.IO ✅ User registration and authentication ✅ Direct messages and group chats ✅ Media file uploads and management ✅ End-to-end encryption ✅ Push notifications ✅ Mention alerts ✅ Typing indicators ✅ Message read receipts ✅ Online status tracking ✅ File access control ✅ Comprehensive API documentation Ready for Flutter SDK development and production deployment.
59 lines
1.3 KiB
JavaScript
59 lines
1.3 KiB
JavaScript
'use strict';
|
|
const {Transform, PassThrough} = require('stream');
|
|
const zlib = require('zlib');
|
|
const mimicResponse = require('mimic-response');
|
|
|
|
module.exports = response => {
|
|
const contentEncoding = (response.headers['content-encoding'] || '').toLowerCase();
|
|
|
|
if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) {
|
|
return response;
|
|
}
|
|
|
|
// TODO: Remove this when targeting Node.js 12.
|
|
const isBrotli = contentEncoding === 'br';
|
|
if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') {
|
|
response.destroy(new Error('Brotli is not supported on Node.js < 12'));
|
|
return response;
|
|
}
|
|
|
|
let isEmpty = true;
|
|
|
|
const checker = new Transform({
|
|
transform(data, _encoding, callback) {
|
|
isEmpty = false;
|
|
|
|
callback(null, data);
|
|
},
|
|
|
|
flush(callback) {
|
|
callback();
|
|
}
|
|
});
|
|
|
|
const finalStream = new PassThrough({
|
|
autoDestroy: false,
|
|
destroy(error, callback) {
|
|
response.destroy();
|
|
|
|
callback(error);
|
|
}
|
|
});
|
|
|
|
const decompressStream = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip();
|
|
|
|
decompressStream.once('error', error => {
|
|
if (isEmpty && !response.readable) {
|
|
finalStream.end();
|
|
return;
|
|
}
|
|
|
|
finalStream.destroy(error);
|
|
});
|
|
|
|
mimicResponse(response, finalStream);
|
|
response.pipe(checker).pipe(decompressStream).pipe(finalStream);
|
|
|
|
return finalStream;
|
|
};
|