
- 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.
207 lines
8.9 KiB
JavaScript
207 lines
8.9 KiB
JavaScript
import { TransformationType } from './enums';
|
|
/**
|
|
* Storage all library metadata.
|
|
*/
|
|
export class MetadataStorage {
|
|
constructor() {
|
|
// -------------------------------------------------------------------------
|
|
// Properties
|
|
// -------------------------------------------------------------------------
|
|
this._typeMetadatas = new Map();
|
|
this._transformMetadatas = new Map();
|
|
this._exposeMetadatas = new Map();
|
|
this._excludeMetadatas = new Map();
|
|
this._ancestorsMap = new Map();
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
// Adder Methods
|
|
// -------------------------------------------------------------------------
|
|
addTypeMetadata(metadata) {
|
|
if (!this._typeMetadatas.has(metadata.target)) {
|
|
this._typeMetadatas.set(metadata.target, new Map());
|
|
}
|
|
this._typeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
|
|
}
|
|
addTransformMetadata(metadata) {
|
|
if (!this._transformMetadatas.has(metadata.target)) {
|
|
this._transformMetadatas.set(metadata.target, new Map());
|
|
}
|
|
if (!this._transformMetadatas.get(metadata.target).has(metadata.propertyName)) {
|
|
this._transformMetadatas.get(metadata.target).set(metadata.propertyName, []);
|
|
}
|
|
this._transformMetadatas.get(metadata.target).get(metadata.propertyName).push(metadata);
|
|
}
|
|
addExposeMetadata(metadata) {
|
|
if (!this._exposeMetadatas.has(metadata.target)) {
|
|
this._exposeMetadatas.set(metadata.target, new Map());
|
|
}
|
|
this._exposeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
|
|
}
|
|
addExcludeMetadata(metadata) {
|
|
if (!this._excludeMetadatas.has(metadata.target)) {
|
|
this._excludeMetadatas.set(metadata.target, new Map());
|
|
}
|
|
this._excludeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
// Public Methods
|
|
// -------------------------------------------------------------------------
|
|
findTransformMetadatas(target, propertyName, transformationType) {
|
|
return this.findMetadatas(this._transformMetadatas, target, propertyName).filter(metadata => {
|
|
if (!metadata.options)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true) {
|
|
return (transformationType === TransformationType.CLASS_TO_CLASS ||
|
|
transformationType === TransformationType.PLAIN_TO_CLASS);
|
|
}
|
|
if (metadata.options.toPlainOnly === true) {
|
|
return transformationType === TransformationType.CLASS_TO_PLAIN;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
findExcludeMetadata(target, propertyName) {
|
|
return this.findMetadata(this._excludeMetadatas, target, propertyName);
|
|
}
|
|
findExposeMetadata(target, propertyName) {
|
|
return this.findMetadata(this._exposeMetadatas, target, propertyName);
|
|
}
|
|
findExposeMetadataByCustomName(target, name) {
|
|
return this.getExposedMetadatas(target).find(metadata => {
|
|
return metadata.options && metadata.options.name === name;
|
|
});
|
|
}
|
|
findTypeMetadata(target, propertyName) {
|
|
return this.findMetadata(this._typeMetadatas, target, propertyName);
|
|
}
|
|
getStrategy(target) {
|
|
const excludeMap = this._excludeMetadatas.get(target);
|
|
const exclude = excludeMap && excludeMap.get(undefined);
|
|
const exposeMap = this._exposeMetadatas.get(target);
|
|
const expose = exposeMap && exposeMap.get(undefined);
|
|
if ((exclude && expose) || (!exclude && !expose))
|
|
return 'none';
|
|
return exclude ? 'excludeAll' : 'exposeAll';
|
|
}
|
|
getExposedMetadatas(target) {
|
|
return this.getMetadata(this._exposeMetadatas, target);
|
|
}
|
|
getExcludedMetadatas(target) {
|
|
return this.getMetadata(this._excludeMetadatas, target);
|
|
}
|
|
getExposedProperties(target, transformationType) {
|
|
return this.getExposedMetadatas(target)
|
|
.filter(metadata => {
|
|
if (!metadata.options)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true) {
|
|
return (transformationType === TransformationType.CLASS_TO_CLASS ||
|
|
transformationType === TransformationType.PLAIN_TO_CLASS);
|
|
}
|
|
if (metadata.options.toPlainOnly === true) {
|
|
return transformationType === TransformationType.CLASS_TO_PLAIN;
|
|
}
|
|
return true;
|
|
})
|
|
.map(metadata => metadata.propertyName);
|
|
}
|
|
getExcludedProperties(target, transformationType) {
|
|
return this.getExcludedMetadatas(target)
|
|
.filter(metadata => {
|
|
if (!metadata.options)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true) {
|
|
return (transformationType === TransformationType.CLASS_TO_CLASS ||
|
|
transformationType === TransformationType.PLAIN_TO_CLASS);
|
|
}
|
|
if (metadata.options.toPlainOnly === true) {
|
|
return transformationType === TransformationType.CLASS_TO_PLAIN;
|
|
}
|
|
return true;
|
|
})
|
|
.map(metadata => metadata.propertyName);
|
|
}
|
|
clear() {
|
|
this._typeMetadatas.clear();
|
|
this._exposeMetadatas.clear();
|
|
this._excludeMetadatas.clear();
|
|
this._ancestorsMap.clear();
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
// Private Methods
|
|
// -------------------------------------------------------------------------
|
|
getMetadata(metadatas, target) {
|
|
const metadataFromTargetMap = metadatas.get(target);
|
|
let metadataFromTarget;
|
|
if (metadataFromTargetMap) {
|
|
metadataFromTarget = Array.from(metadataFromTargetMap.values()).filter(meta => meta.propertyName !== undefined);
|
|
}
|
|
const metadataFromAncestors = [];
|
|
for (const ancestor of this.getAncestors(target)) {
|
|
const ancestorMetadataMap = metadatas.get(ancestor);
|
|
if (ancestorMetadataMap) {
|
|
const metadataFromAncestor = Array.from(ancestorMetadataMap.values()).filter(meta => meta.propertyName !== undefined);
|
|
metadataFromAncestors.push(...metadataFromAncestor);
|
|
}
|
|
}
|
|
return metadataFromAncestors.concat(metadataFromTarget || []);
|
|
}
|
|
findMetadata(metadatas, target, propertyName) {
|
|
const metadataFromTargetMap = metadatas.get(target);
|
|
if (metadataFromTargetMap) {
|
|
const metadataFromTarget = metadataFromTargetMap.get(propertyName);
|
|
if (metadataFromTarget) {
|
|
return metadataFromTarget;
|
|
}
|
|
}
|
|
for (const ancestor of this.getAncestors(target)) {
|
|
const ancestorMetadataMap = metadatas.get(ancestor);
|
|
if (ancestorMetadataMap) {
|
|
const ancestorResult = ancestorMetadataMap.get(propertyName);
|
|
if (ancestorResult) {
|
|
return ancestorResult;
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
findMetadatas(metadatas, target, propertyName) {
|
|
const metadataFromTargetMap = metadatas.get(target);
|
|
let metadataFromTarget;
|
|
if (metadataFromTargetMap) {
|
|
metadataFromTarget = metadataFromTargetMap.get(propertyName);
|
|
}
|
|
const metadataFromAncestorsTarget = [];
|
|
for (const ancestor of this.getAncestors(target)) {
|
|
const ancestorMetadataMap = metadatas.get(ancestor);
|
|
if (ancestorMetadataMap) {
|
|
if (ancestorMetadataMap.has(propertyName)) {
|
|
metadataFromAncestorsTarget.push(...ancestorMetadataMap.get(propertyName));
|
|
}
|
|
}
|
|
}
|
|
return metadataFromAncestorsTarget
|
|
.slice()
|
|
.reverse()
|
|
.concat((metadataFromTarget || []).slice().reverse());
|
|
}
|
|
getAncestors(target) {
|
|
if (!target)
|
|
return [];
|
|
if (!this._ancestorsMap.has(target)) {
|
|
const ancestors = [];
|
|
for (let baseClass = Object.getPrototypeOf(target.prototype.constructor); typeof baseClass.prototype !== 'undefined'; baseClass = Object.getPrototypeOf(baseClass.prototype.constructor)) {
|
|
ancestors.push(baseClass);
|
|
}
|
|
this._ancestorsMap.set(target, ancestors);
|
|
}
|
|
return this._ancestorsMap.get(target);
|
|
}
|
|
}
|
|
//# sourceMappingURL=MetadataStorage.js.map
|