@flusys/nestjs-notification 3.0.1

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 (80) hide show
  1. package/README.md +998 -0
  2. package/adapters/index.d.ts +1 -0
  3. package/adapters/notification.adapter.d.ts +10 -0
  4. package/cjs/adapters/index.js +18 -0
  5. package/cjs/adapters/notification.adapter.js +79 -0
  6. package/cjs/config/index.js +18 -0
  7. package/cjs/config/notification.constants.js +11 -0
  8. package/cjs/controllers/index.js +18 -0
  9. package/cjs/controllers/notification.controller.js +278 -0
  10. package/cjs/docs/index.js +18 -0
  11. package/cjs/docs/notification-swagger.config.js +61 -0
  12. package/cjs/dtos/index.js +18 -0
  13. package/cjs/dtos/notification.dto.js +244 -0
  14. package/cjs/entities/index.js +48 -0
  15. package/cjs/entities/notification-with-company.entity.js +57 -0
  16. package/cjs/entities/notification.entity.js +111 -0
  17. package/cjs/gateways/index.js +18 -0
  18. package/cjs/gateways/notification.gateway.js +226 -0
  19. package/cjs/index.js +28 -0
  20. package/cjs/interfaces/index.js +19 -0
  21. package/cjs/interfaces/notification-module.interface.js +4 -0
  22. package/cjs/interfaces/notification.interface.js +4 -0
  23. package/cjs/modules/index.js +18 -0
  24. package/cjs/modules/notification.module.js +139 -0
  25. package/cjs/services/index.js +21 -0
  26. package/cjs/services/notification-config.service.js +72 -0
  27. package/cjs/services/notification-datasource.provider.js +174 -0
  28. package/cjs/services/notification-helper.service.js +186 -0
  29. package/cjs/services/notification.service.js +220 -0
  30. package/config/index.d.ts +1 -0
  31. package/config/notification.constants.d.ts +1 -0
  32. package/controllers/index.d.ts +1 -0
  33. package/controllers/notification.controller.d.ts +26 -0
  34. package/docs/index.d.ts +1 -0
  35. package/docs/notification-swagger.config.d.ts +2 -0
  36. package/dtos/index.d.ts +1 -0
  37. package/dtos/notification.dto.d.ts +47 -0
  38. package/entities/index.d.ts +8 -0
  39. package/entities/notification-with-company.entity.d.ts +4 -0
  40. package/entities/notification.entity.d.ts +10 -0
  41. package/fesm/adapters/index.js +1 -0
  42. package/fesm/adapters/notification.adapter.js +69 -0
  43. package/fesm/config/index.js +1 -0
  44. package/fesm/config/notification.constants.js +1 -0
  45. package/fesm/controllers/index.js +1 -0
  46. package/fesm/controllers/notification.controller.js +268 -0
  47. package/fesm/docs/index.js +1 -0
  48. package/fesm/docs/notification-swagger.config.js +51 -0
  49. package/fesm/dtos/index.js +1 -0
  50. package/fesm/dtos/notification.dto.js +211 -0
  51. package/fesm/entities/index.js +14 -0
  52. package/fesm/entities/notification-with-company.entity.js +47 -0
  53. package/fesm/entities/notification.entity.js +101 -0
  54. package/fesm/gateways/index.js +1 -0
  55. package/fesm/gateways/notification.gateway.js +175 -0
  56. package/fesm/index.js +20 -0
  57. package/fesm/interfaces/index.js +2 -0
  58. package/fesm/interfaces/notification-module.interface.js +1 -0
  59. package/fesm/interfaces/notification.interface.js +1 -0
  60. package/fesm/modules/index.js +1 -0
  61. package/fesm/modules/notification.module.js +129 -0
  62. package/fesm/services/index.js +4 -0
  63. package/fesm/services/notification-config.service.js +62 -0
  64. package/fesm/services/notification-datasource.provider.js +123 -0
  65. package/fesm/services/notification-helper.service.js +176 -0
  66. package/fesm/services/notification.service.js +210 -0
  67. package/gateways/index.d.ts +1 -0
  68. package/gateways/notification.gateway.d.ts +21 -0
  69. package/index.d.ts +10 -0
  70. package/interfaces/index.d.ts +2 -0
  71. package/interfaces/notification-module.interface.d.ts +20 -0
  72. package/interfaces/notification.interface.d.ts +19 -0
  73. package/modules/index.d.ts +1 -0
  74. package/modules/notification.module.d.ts +8 -0
  75. package/package.json +98 -0
  76. package/services/index.d.ts +4 -0
  77. package/services/notification-config.service.d.ts +13 -0
  78. package/services/notification-datasource.provider.d.ts +23 -0
  79. package/services/notification-helper.service.d.ts +44 -0
  80. package/services/notification.service.d.ts +35 -0
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "NotificationDataSourceProvider", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return NotificationDataSourceProvider;
9
+ }
10
+ });
11
+ const _modules = require("@flusys/nestjs-shared/modules");
12
+ const _common = require("@nestjs/common");
13
+ const _core = require("@nestjs/core");
14
+ const _express = require("express");
15
+ const _notificationconfigservice = require("./notification-config.service");
16
+ function _define_property(obj, key, value) {
17
+ if (key in obj) {
18
+ Object.defineProperty(obj, key, {
19
+ value: value,
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true
23
+ });
24
+ } else {
25
+ obj[key] = value;
26
+ }
27
+ return obj;
28
+ }
29
+ function _getRequireWildcardCache(nodeInterop) {
30
+ if (typeof WeakMap !== "function") return null;
31
+ var cacheBabelInterop = new WeakMap();
32
+ var cacheNodeInterop = new WeakMap();
33
+ return (_getRequireWildcardCache = function(nodeInterop) {
34
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
35
+ })(nodeInterop);
36
+ }
37
+ function _interop_require_wildcard(obj, nodeInterop) {
38
+ if (!nodeInterop && obj && obj.__esModule) {
39
+ return obj;
40
+ }
41
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
42
+ return {
43
+ default: obj
44
+ };
45
+ }
46
+ var cache = _getRequireWildcardCache(nodeInterop);
47
+ if (cache && cache.has(obj)) {
48
+ return cache.get(obj);
49
+ }
50
+ var newObj = {
51
+ __proto__: null
52
+ };
53
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
54
+ for(var key in obj){
55
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
56
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
57
+ if (desc && (desc.get || desc.set)) {
58
+ Object.defineProperty(newObj, key, desc);
59
+ } else {
60
+ newObj[key] = obj[key];
61
+ }
62
+ }
63
+ }
64
+ newObj.default = obj;
65
+ if (cache) {
66
+ cache.set(obj, newObj);
67
+ }
68
+ return newObj;
69
+ }
70
+ function _ts_decorate(decorators, target, key, desc) {
71
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
72
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
73
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
74
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
75
+ }
76
+ function _ts_metadata(k, v) {
77
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
78
+ }
79
+ function _ts_param(paramIndex, decorator) {
80
+ return function(target, key) {
81
+ decorator(target, key, paramIndex);
82
+ };
83
+ }
84
+ let NotificationDataSourceProvider = class NotificationDataSourceProvider extends _modules.MultiTenantDataSourceService {
85
+ static buildParentOptions(options) {
86
+ return {
87
+ bootstrapAppConfig: options.bootstrapAppConfig,
88
+ defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
89
+ tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
90
+ tenants: options.config?.tenants
91
+ };
92
+ }
93
+ getEnableCompanyFeatureForTenant(tenant) {
94
+ return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
95
+ }
96
+ async getNotificationEntities(enableCompanyFeature) {
97
+ const enable = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
98
+ const entities = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
99
+ return enable ? [
100
+ entities.NotificationWithCompany
101
+ ] : [
102
+ entities.Notification
103
+ ];
104
+ }
105
+ async createDataSourceFromConfig(config) {
106
+ const currentTenant = this.getCurrentTenant();
107
+ const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
108
+ const entities = await this.getNotificationEntities(enableCompanyFeature);
109
+ return super.createDataSourceFromConfig(config, entities);
110
+ }
111
+ async getSingleDataSource() {
112
+ if (NotificationDataSourceProvider.singleDataSource?.isInitialized) {
113
+ return NotificationDataSourceProvider.singleDataSource;
114
+ }
115
+ if (NotificationDataSourceProvider.singleConnectionLock) {
116
+ return NotificationDataSourceProvider.singleConnectionLock;
117
+ }
118
+ const config = this.getDefaultDatabaseConfig();
119
+ if (!config) {
120
+ throw new _common.InternalServerErrorException('No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.');
121
+ }
122
+ const connectionPromise = this.createDataSourceFromConfig(config);
123
+ NotificationDataSourceProvider.singleConnectionLock = connectionPromise;
124
+ try {
125
+ const dataSource = await connectionPromise;
126
+ NotificationDataSourceProvider.singleDataSource = dataSource;
127
+ return dataSource;
128
+ } finally{
129
+ NotificationDataSourceProvider.singleConnectionLock = null;
130
+ }
131
+ }
132
+ async getOrCreateTenantConnection(tenant) {
133
+ const existing = NotificationDataSourceProvider.tenantConnections.get(tenant.id);
134
+ if (existing?.isInitialized) {
135
+ return existing;
136
+ }
137
+ const pendingConnection = NotificationDataSourceProvider.connectionLocks.get(tenant.id);
138
+ if (pendingConnection) {
139
+ return pendingConnection;
140
+ }
141
+ const config = this.buildTenantDatabaseConfig(tenant);
142
+ const connectionPromise = this.createDataSourceFromConfig(config);
143
+ NotificationDataSourceProvider.connectionLocks.set(tenant.id, connectionPromise);
144
+ try {
145
+ const dataSource = await connectionPromise;
146
+ NotificationDataSourceProvider.tenantConnections.set(tenant.id, dataSource);
147
+ return dataSource;
148
+ } finally{
149
+ NotificationDataSourceProvider.connectionLocks.delete(tenant.id);
150
+ }
151
+ }
152
+ constructor(configService, request){
153
+ super(NotificationDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), _define_property(this, "logger", void 0), this.configService = configService, this.logger = new _common.Logger(NotificationDataSourceProvider.name);
154
+ }
155
+ };
156
+ _define_property(NotificationDataSourceProvider, "tenantConnections", new Map());
157
+ _define_property(NotificationDataSourceProvider, "singleDataSource", null);
158
+ _define_property(NotificationDataSourceProvider, "tenantsRegistry", new Map());
159
+ _define_property(NotificationDataSourceProvider, "initialized", false);
160
+ _define_property(NotificationDataSourceProvider, "connectionLocks", new Map());
161
+ _define_property(NotificationDataSourceProvider, "singleConnectionLock", null);
162
+ NotificationDataSourceProvider = _ts_decorate([
163
+ (0, _common.Injectable)({
164
+ scope: _common.Scope.REQUEST
165
+ }),
166
+ _ts_param(0, (0, _common.Inject)(_notificationconfigservice.NotificationConfigService)),
167
+ _ts_param(1, (0, _common.Optional)()),
168
+ _ts_param(1, (0, _common.Inject)(_core.REQUEST)),
169
+ _ts_metadata("design:type", Function),
170
+ _ts_metadata("design:paramtypes", [
171
+ typeof _notificationconfigservice.NotificationConfigService === "undefined" ? Object : _notificationconfigservice.NotificationConfigService,
172
+ typeof _express.Request === "undefined" ? Object : _express.Request
173
+ ])
174
+ ], NotificationDataSourceProvider);
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "NotificationHelperService", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return NotificationHelperService;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ const _classes = require("@flusys/nestjs-shared/classes");
13
+ const _modules = require("@flusys/nestjs-shared/modules");
14
+ const _notificationconfigservice = require("./notification-config.service");
15
+ const _notificationdatasourceprovider = require("./notification-datasource.provider");
16
+ const _gateways = require("../gateways");
17
+ const _entities = require("../entities");
18
+ const _enums = require("@flusys/nestjs-shared/enums");
19
+ function _define_property(obj, key, value) {
20
+ if (key in obj) {
21
+ Object.defineProperty(obj, key, {
22
+ value: value,
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true
26
+ });
27
+ } else {
28
+ obj[key] = value;
29
+ }
30
+ return obj;
31
+ }
32
+ function _ts_decorate(decorators, target, key, desc) {
33
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
34
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
35
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
36
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
37
+ }
38
+ function _ts_metadata(k, v) {
39
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
40
+ }
41
+ function _ts_param(paramIndex, decorator) {
42
+ return function(target, key) {
43
+ decorator(target, key, paramIndex);
44
+ };
45
+ }
46
+ let NotificationHelperService = class NotificationHelperService {
47
+ async getDataSource() {
48
+ if (!this.dataSource) {
49
+ this.dataSource = await this.dataSourceProvider.getDataSource();
50
+ }
51
+ return this.dataSource;
52
+ }
53
+ async getRepository() {
54
+ const ds = await this.getDataSource();
55
+ const EntityClass = this.configService.isCompanyFeatureEnabled() ? _entities.NotificationWithCompany : _entities.Notification;
56
+ return ds.getRepository(EntityClass);
57
+ }
58
+ async send(options) {
59
+ const { userId, title, message = null, type = _enums.NotificationType.INFO, data = null, companyId } = options;
60
+ const repo = await this.getRepository();
61
+ const entity = {
62
+ userId,
63
+ type,
64
+ title,
65
+ message,
66
+ data,
67
+ isRead: false
68
+ };
69
+ if (this.configService.isCompanyFeatureEnabled() && companyId) {
70
+ entity.companyId = companyId;
71
+ }
72
+ const saved = await repo.save(entity);
73
+ await this.clearCache();
74
+ this.emitRealtime(saved);
75
+ this.logger.debug(`Notification sent to user ${userId}: ${title}`);
76
+ return saved;
77
+ }
78
+ async sendToMany(options) {
79
+ const { userIds, title, message = null, type = _enums.NotificationType.INFO, data = null, companyId } = options;
80
+ const repo = await this.getRepository();
81
+ const entities = userIds.map((userId)=>({
82
+ userId,
83
+ type,
84
+ title,
85
+ message,
86
+ data,
87
+ isRead: false,
88
+ ...this.configService.isCompanyFeatureEnabled() && companyId ? {
89
+ companyId
90
+ } : {}
91
+ }));
92
+ const saved = await repo.save(entities);
93
+ await this.clearCache();
94
+ for (const notification of saved){
95
+ this.emitRealtime(notification);
96
+ }
97
+ this.logger.debug(`Notification sent to ${userIds.length} users: ${title}`);
98
+ return saved;
99
+ }
100
+ async sendToCompany(companyId, title, message, type = _enums.NotificationType.INFO, data) {
101
+ if (!this.configService.isCompanyFeatureEnabled()) {
102
+ this.logger.warn('sendToCompany called but company feature is disabled');
103
+ return;
104
+ }
105
+ if (this.configService.isRealtimeEnabled() && this.gateway) {
106
+ const payload = {
107
+ id: `broadcast-${Date.now()}`,
108
+ type,
109
+ title,
110
+ message: message ?? null,
111
+ data: data ?? null,
112
+ createdAt: new Date()
113
+ };
114
+ this.gateway.emitToCompany(companyId, 'notification:new', payload);
115
+ this.logger.debug(`Broadcast notification sent to company ${companyId}: ${title}`);
116
+ }
117
+ }
118
+ isUserOnline(userId) {
119
+ return this.gateway?.isUserOnline(userId) ?? false;
120
+ }
121
+ getOnlineUserCount() {
122
+ return this.gateway?.getOnlineUserCount() ?? 0;
123
+ }
124
+ emitRealtime(notification) {
125
+ if (!this.configService.isRealtimeEnabled() || !this.gateway) {
126
+ return;
127
+ }
128
+ const ext = notification;
129
+ const payload = this.toPayload(notification);
130
+ if (this.configService.isCompanyFeatureEnabled() && ext.companyId) {
131
+ // Company feature enabled - emit only to sockets in matching company context
132
+ this.gateway.emitToUserInCompany(notification.userId, ext.companyId, 'notification:new', payload);
133
+ } else {
134
+ // No company feature or no companyId - emit to all user's sockets
135
+ this.gateway.emitToUser(notification.userId, 'notification:new', payload);
136
+ }
137
+ }
138
+ toPayload(notification) {
139
+ return {
140
+ id: notification.id,
141
+ type: notification.type,
142
+ title: notification.title,
143
+ message: notification.message,
144
+ data: notification.data,
145
+ createdAt: notification.createdAt
146
+ };
147
+ }
148
+ async clearCache() {
149
+ await this.utilsService.clearCache(this.entityName, this.cacheManager);
150
+ }
151
+ constructor(cacheManager, utilsService, configService, dataSourceProvider, gateway){
152
+ _define_property(this, "cacheManager", void 0);
153
+ _define_property(this, "utilsService", void 0);
154
+ _define_property(this, "configService", void 0);
155
+ _define_property(this, "dataSourceProvider", void 0);
156
+ _define_property(this, "gateway", void 0);
157
+ _define_property(this, "logger", void 0);
158
+ _define_property(this, "entityName", void 0);
159
+ _define_property(this, "dataSource", void 0);
160
+ this.cacheManager = cacheManager;
161
+ this.utilsService = utilsService;
162
+ this.configService = configService;
163
+ this.dataSourceProvider = dataSourceProvider;
164
+ this.gateway = gateway;
165
+ this.logger = new _common.Logger(NotificationHelperService.name);
166
+ this.entityName = 'notification';
167
+ this.dataSource = null;
168
+ }
169
+ };
170
+ NotificationHelperService = _ts_decorate([
171
+ (0, _common.Injectable)(),
172
+ _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
173
+ _ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
174
+ _ts_param(2, (0, _common.Inject)(_notificationconfigservice.NotificationConfigService)),
175
+ _ts_param(3, (0, _common.Inject)(_notificationdatasourceprovider.NotificationDataSourceProvider)),
176
+ _ts_param(4, (0, _common.Optional)()),
177
+ _ts_param(4, (0, _common.Inject)(_gateways.NotificationGateway)),
178
+ _ts_metadata("design:type", Function),
179
+ _ts_metadata("design:paramtypes", [
180
+ typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
181
+ typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
182
+ typeof _notificationconfigservice.NotificationConfigService === "undefined" ? Object : _notificationconfigservice.NotificationConfigService,
183
+ typeof _notificationdatasourceprovider.NotificationDataSourceProvider === "undefined" ? Object : _notificationdatasourceprovider.NotificationDataSourceProvider,
184
+ typeof _gateways.NotificationGateway === "undefined" ? Object : _gateways.NotificationGateway
185
+ ])
186
+ ], NotificationHelperService);
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "NotificationService", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return NotificationService;
9
+ }
10
+ });
11
+ const _classes = require("@flusys/nestjs-shared/classes");
12
+ const _modules = require("@flusys/nestjs-shared/modules");
13
+ const _utils = require("@flusys/nestjs-shared/utils");
14
+ const _common = require("@nestjs/common");
15
+ const _entities = require("../entities");
16
+ const _gateways = require("../gateways");
17
+ const _notificationconfigservice = require("./notification-config.service");
18
+ const _notificationdatasourceprovider = require("./notification-datasource.provider");
19
+ function _define_property(obj, key, value) {
20
+ if (key in obj) {
21
+ Object.defineProperty(obj, key, {
22
+ value: value,
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true
26
+ });
27
+ } else {
28
+ obj[key] = value;
29
+ }
30
+ return obj;
31
+ }
32
+ function _ts_decorate(decorators, target, key, desc) {
33
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
34
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
35
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
36
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
37
+ }
38
+ function _ts_metadata(k, v) {
39
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
40
+ }
41
+ function _ts_param(paramIndex, decorator) {
42
+ return function(target, key) {
43
+ decorator(target, key, paramIndex);
44
+ };
45
+ }
46
+ let NotificationService = class NotificationService extends _classes.RequestScopedApiService {
47
+ resolveEntity() {
48
+ return this.notificationConfig.isCompanyFeatureEnabled() ? _entities.NotificationWithCompany : _entities.Notification;
49
+ }
50
+ getDataSourceProvider() {
51
+ return this.dataSourceProvider;
52
+ }
53
+ async convertSingleDtoToEntity(dto, user) {
54
+ let entity = {};
55
+ if ('id' in dto && dto.id) {
56
+ const existing = await this.repository.findOne({
57
+ where: {
58
+ id: dto.id
59
+ }
60
+ });
61
+ if (!existing) throw new _common.NotFoundException('Notification not found');
62
+ entity = existing;
63
+ }
64
+ const merged = {
65
+ ...entity,
66
+ userId: user?.id ?? entity.userId,
67
+ type: dto.type ?? entity.type ?? 'info',
68
+ title: dto.title ?? entity.title,
69
+ message: dto.message ?? entity.message,
70
+ data: dto.data ?? entity.data,
71
+ isRead: entity.isRead ?? false,
72
+ readAt: entity.readAt
73
+ };
74
+ if (this.notificationConfig.isCompanyFeatureEnabled()) {
75
+ merged.companyId = dto.companyId ?? user?.companyId ?? entity.companyId ?? null;
76
+ }
77
+ return merged;
78
+ }
79
+ async getFilterQuery(query, filter, _user) {
80
+ for (const [key, value] of Object.entries(filter)){
81
+ if (key === 'isRead' && typeof value === 'boolean') {
82
+ query.andWhere(`${this.entityName}.isRead = :isRead`, {
83
+ isRead: value
84
+ });
85
+ } else if (key === 'type' && value) {
86
+ query.andWhere(`${this.entityName}.type = :type`, {
87
+ type: value
88
+ });
89
+ } else if (key === 'userId' && value) {
90
+ query.andWhere(`${this.entityName}.userId = :userId`, {
91
+ userId: value
92
+ });
93
+ }
94
+ }
95
+ return {
96
+ query,
97
+ isRaw: false
98
+ };
99
+ }
100
+ async getExtraManipulateQuery(query, filterDto, user) {
101
+ const result = await super.getExtraManipulateQuery(query, filterDto, user);
102
+ if (user?.id) {
103
+ query.andWhere(`${this.entityName}.userId = :currentUserId`, {
104
+ currentUserId: user.id
105
+ });
106
+ }
107
+ (0, _utils.applyCompanyFilter)(query, {
108
+ isCompanyFeatureEnabled: this.notificationConfig.isCompanyFeatureEnabled(),
109
+ entityAlias: this.entityName
110
+ }, user);
111
+ if (!filterDto?.sort || Object.keys(filterDto.sort).length === 0) {
112
+ query.orderBy(`${this.entityName}.createdAt`, 'DESC');
113
+ }
114
+ return result;
115
+ }
116
+ async afterInsertOperation(entities, _user, _qr) {
117
+ for (const entity of entities){
118
+ const ext = entity;
119
+ this.emitToUserInCompanyIfRealtime(entity.userId, ext.companyId, 'notification:new', this.toPayload(entity));
120
+ }
121
+ }
122
+ async markAsRead(id, user) {
123
+ await this.ensureRepositoryInitialized();
124
+ const notification = await this.repository.findOne({
125
+ where: {
126
+ id,
127
+ userId: user.id
128
+ }
129
+ });
130
+ if (!notification) {
131
+ throw new _common.NotFoundException('Notification not found');
132
+ }
133
+ notification.isRead = true;
134
+ notification.readAt = new Date();
135
+ await this.repository.save(notification);
136
+ await Promise.all([
137
+ this.clearCacheForAll(),
138
+ this.clearCacheForId([
139
+ notification
140
+ ])
141
+ ]);
142
+ // Emit to user's sockets in the same company context
143
+ const ext = notification;
144
+ this.emitToUserInCompanyIfRealtime(user.id, ext.companyId ?? user.companyId, 'notification:read', {
145
+ id
146
+ });
147
+ return notification;
148
+ }
149
+ async markAllAsRead(user) {
150
+ await this.ensureRepositoryInitialized();
151
+ const result = await this.repository.update({
152
+ userId: user.id,
153
+ isRead: false
154
+ }, {
155
+ isRead: true,
156
+ readAt: new Date()
157
+ });
158
+ await this.clearCacheForAll();
159
+ // Emit to user's sockets in the current company context
160
+ this.emitToUserInCompanyIfRealtime(user.id, user.companyId, 'notification:read-all', {});
161
+ return result.affected ?? 0;
162
+ }
163
+ async getUnreadCount(user) {
164
+ await this.ensureRepositoryInitialized();
165
+ return this.repository.count({
166
+ where: {
167
+ userId: user.id,
168
+ isRead: false
169
+ }
170
+ });
171
+ }
172
+ toPayload(entity) {
173
+ return {
174
+ id: entity.id,
175
+ type: entity.type,
176
+ title: entity.title,
177
+ message: entity.message,
178
+ data: entity.data,
179
+ createdAt: entity.createdAt
180
+ };
181
+ }
182
+ /**
183
+ * Emit to user's sockets within a specific company context.
184
+ * If company feature is enabled and companyId is provided, only sockets
185
+ * connected with that company will receive the event.
186
+ */ emitToUserInCompanyIfRealtime(userId, companyId, event, payload) {
187
+ if (!this.notificationConfig.isRealtimeEnabled() || !this.gateway) {
188
+ return;
189
+ }
190
+ if (this.notificationConfig.isCompanyFeatureEnabled() && companyId) {
191
+ // Company feature enabled - emit only to sockets in matching company context
192
+ this.gateway.emitToUserInCompany(userId, companyId, event, payload);
193
+ } else {
194
+ // No company feature or no companyId - emit to all user's sockets
195
+ this.gateway.emitToUser(userId, event, payload);
196
+ }
197
+ }
198
+ constructor(cacheManager, utilsService, notificationConfig, dataSourceProvider, gateway){
199
+ super('notification', null, cacheManager, utilsService, NotificationService.name, false), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "notificationConfig", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "gateway", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.notificationConfig = notificationConfig, this.dataSourceProvider = dataSourceProvider, this.gateway = gateway;
200
+ }
201
+ };
202
+ NotificationService = _ts_decorate([
203
+ (0, _common.Injectable)({
204
+ scope: _common.Scope.REQUEST
205
+ }),
206
+ _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
207
+ _ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
208
+ _ts_param(2, (0, _common.Inject)(_notificationconfigservice.NotificationConfigService)),
209
+ _ts_param(3, (0, _common.Inject)(_notificationdatasourceprovider.NotificationDataSourceProvider)),
210
+ _ts_param(4, (0, _common.Optional)()),
211
+ _ts_param(4, (0, _common.Inject)(_gateways.NotificationGateway)),
212
+ _ts_metadata("design:type", Function),
213
+ _ts_metadata("design:paramtypes", [
214
+ typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
215
+ typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
216
+ typeof _notificationconfigservice.NotificationConfigService === "undefined" ? Object : _notificationconfigservice.NotificationConfigService,
217
+ typeof _notificationdatasourceprovider.NotificationDataSourceProvider === "undefined" ? Object : _notificationdatasourceprovider.NotificationDataSourceProvider,
218
+ typeof _gateways.NotificationGateway === "undefined" ? Object : _gateways.NotificationGateway
219
+ ])
220
+ ], NotificationService);
@@ -0,0 +1 @@
1
+ export * from './notification.constants';
@@ -0,0 +1 @@
1
+ export declare const NOTIFICATION_MODULE_OPTIONS = "NOTIFICATION_MODULE_OPTIONS";
@@ -0,0 +1 @@
1
+ export * from './notification.controller';
@@ -0,0 +1,26 @@
1
+ import { BulkResponseDto, MessageResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
2
+ import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
3
+ import { CreateNotificationDto, MarkReadDto, NotificationResponseDto, SendBulkNotificationDto, SendNotificationDto, UnreadCountResponseDto, UpdateNotificationDto } from '../dtos';
4
+ import { NotificationHelperService } from '../services/notification-helper.service';
5
+ import { NotificationService } from '../services/notification.service';
6
+ declare const NotificationController_base: abstract new (service: NotificationService) => {
7
+ service: NotificationService;
8
+ insert(addDto: CreateNotificationDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
9
+ insertMany(addDto: CreateNotificationDto[], user: ILoggedUserInfo | null): Promise<BulkResponseDto<NotificationResponseDto>>;
10
+ getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
11
+ update(updateDto: UpdateNotificationDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
12
+ updateMany(updateDtos: UpdateNotificationDto[], user: ILoggedUserInfo | null): Promise<BulkResponseDto<NotificationResponseDto>>;
13
+ getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared/dtos").ListResponseDto<NotificationResponseDto>>;
14
+ delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: ILoggedUserInfo | null): Promise<MessageResponseDto>;
15
+ };
16
+ export declare class NotificationController extends NotificationController_base {
17
+ service: NotificationService;
18
+ private readonly notificationHelper;
19
+ constructor(service: NotificationService, notificationHelper: NotificationHelperService);
20
+ markAsRead(dto: MarkReadDto, user: ILoggedUserInfo): Promise<SingleResponseDto<NotificationResponseDto>>;
21
+ markAllAsRead(user: ILoggedUserInfo): Promise<MessageResponseDto>;
22
+ getUnreadCount(user: ILoggedUserInfo): Promise<SingleResponseDto<UnreadCountResponseDto>>;
23
+ sendNotification(dto: SendNotificationDto): Promise<SingleResponseDto<NotificationResponseDto>>;
24
+ sendBulkNotification(dto: SendBulkNotificationDto): Promise<BulkResponseDto<NotificationResponseDto>>;
25
+ }
26
+ export {};
@@ -0,0 +1 @@
1
+ export * from './notification-swagger.config';
@@ -0,0 +1,2 @@
1
+ import { IModuleSwaggerOptions } from '@flusys/nestjs-core/docs';
2
+ export declare function notificationSwaggerConfig(): IModuleSwaggerOptions;
@@ -0,0 +1 @@
1
+ export * from './notification.dto';
@@ -0,0 +1,47 @@
1
+ import { NotificationType } from '@flusys/nestjs-shared/enums';
2
+ declare class NotificationContentDto {
3
+ title: string;
4
+ message?: string;
5
+ type?: NotificationType;
6
+ data?: Record<string, unknown>;
7
+ companyId?: string;
8
+ }
9
+ declare class UserIdDto {
10
+ userId: string;
11
+ }
12
+ declare class UserIdsDto {
13
+ userIds: string[];
14
+ }
15
+ declare const CreateNotificationDto_base: import("@nestjs/common").Type<NotificationContentDto & UserIdDto>;
16
+ export declare class CreateNotificationDto extends CreateNotificationDto_base {
17
+ }
18
+ declare const UpdateNotificationDto_base: import("@nestjs/common").Type<Partial<Omit<CreateNotificationDto, "userId">>>;
19
+ export declare class UpdateNotificationDto extends UpdateNotificationDto_base {
20
+ id: string;
21
+ }
22
+ export declare class MarkReadDto {
23
+ id: string;
24
+ }
25
+ export declare class NotificationResponseDto {
26
+ id: string;
27
+ userId: string;
28
+ type: string;
29
+ title: string;
30
+ message?: string | null;
31
+ data?: Record<string, unknown> | null;
32
+ isRead: boolean;
33
+ readAt?: Date | null;
34
+ companyId?: string | null;
35
+ createdAt: Date;
36
+ updatedAt: Date;
37
+ }
38
+ export declare class UnreadCountResponseDto {
39
+ count: number;
40
+ }
41
+ declare const SendNotificationDto_base: import("@nestjs/common").Type<NotificationContentDto & UserIdDto>;
42
+ export declare class SendNotificationDto extends SendNotificationDto_base {
43
+ }
44
+ declare const SendBulkNotificationDto_base: import("@nestjs/common").Type<NotificationContentDto & UserIdsDto>;
45
+ export declare class SendBulkNotificationDto extends SendBulkNotificationDto_base {
46
+ }
47
+ export {};