@flusys/nestjs-event-manager 4.1.0 → 5.0.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.
- package/README.md +126 -337
- package/adapters/event-manager.adapter.d.ts +0 -2
- package/cjs/adapters/event-manager.adapter.js +1 -7
- package/cjs/config/message-keys.js +1 -31
- package/cjs/controllers/event.controller.js +10 -60
- package/cjs/controllers/index.js +0 -1
- package/cjs/docs/event-manager-swagger.config.js +19 -29
- package/cjs/docs/index.js +0 -3
- package/cjs/dtos/calendar-query.dto.js +46 -20
- package/cjs/dtos/event-participant.dto.js +0 -45
- package/cjs/dtos/event.dto.js +97 -45
- package/cjs/entities/event-participant.entity.js +1 -8
- package/cjs/entities/event.entity.js +38 -26
- package/cjs/modules/event-manager.module.js +2 -4
- package/cjs/services/event-manager-helper.service.js +15 -83
- package/cjs/services/event.service.js +143 -122
- package/cjs/services/index.js +0 -1
- package/config/message-keys.d.ts +0 -56
- package/controllers/event.controller.d.ts +2 -5
- package/controllers/index.d.ts +0 -1
- package/docs/index.d.ts +1 -1
- package/dtos/calendar-query.dto.d.ts +8 -5
- package/dtos/event-participant.dto.d.ts +0 -6
- package/dtos/event.dto.d.ts +14 -10
- package/entities/event-participant.entity.d.ts +0 -1
- package/entities/event.entity.d.ts +6 -5
- package/fesm/adapters/event-manager.adapter.js +1 -7
- package/fesm/config/message-keys.js +1 -29
- package/fesm/controllers/event.controller.js +11 -61
- package/fesm/controllers/index.js +0 -1
- package/fesm/docs/event-manager-swagger.config.js +19 -29
- package/fesm/docs/index.js +1 -1
- package/fesm/dtos/calendar-query.dto.js +47 -21
- package/fesm/dtos/event-participant.dto.js +0 -42
- package/fesm/dtos/event.dto.js +98 -46
- package/fesm/entities/event-participant.entity.js +1 -8
- package/fesm/entities/event.entity.js +38 -26
- package/fesm/modules/event-manager.module.js +4 -6
- package/fesm/services/event-manager-helper.service.js +17 -85
- package/fesm/services/event.service.js +144 -123
- package/fesm/services/index.js +0 -1
- package/interfaces/event.interface.d.ts +6 -6
- package/package.json +3 -3
- package/services/event-manager-helper.service.d.ts +1 -3
- package/services/event.service.d.ts +8 -8
- package/services/index.d.ts +0 -1
- package/cjs/controllers/event-participant.controller.js +0 -287
- package/cjs/services/event-participant.service.js +0 -198
- package/controllers/event-participant.controller.d.ts +0 -35
- package/fesm/controllers/event-participant.controller.js +0 -277
- package/fesm/services/event-participant.service.js +0 -188
- package/services/event-participant.service.d.ts +0 -27
package/README.md
CHANGED
|
@@ -1,66 +1,9 @@
|
|
|
1
1
|
# @flusys/nestjs-event-manager
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Calendar event management for NestJS — recurrence patterns (DAILY, WEEKLY, BIWEEKLY, MONTHLY), participant tracking with status, and an `EVENT_MANAGER_ADAPTER` injection token for dependency-free cross-module integration.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@flusys/nestjs-event-manager)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://nestjs.com/)
|
|
8
|
-
[](https://www.typescriptlang.org/)
|
|
9
|
-
[](https://nodejs.org/)
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Table of Contents
|
|
14
|
-
|
|
15
|
-
- [Overview](#overview)
|
|
16
|
-
- [Features](#features)
|
|
17
|
-
- [Compatibility](#compatibility)
|
|
18
|
-
- [Installation](#installation)
|
|
19
|
-
- [Quick Start](#quick-start)
|
|
20
|
-
- [Module Registration](#module-registration)
|
|
21
|
-
- [forRoot (Sync)](#forroot-sync)
|
|
22
|
-
- [forRootAsync (Factory)](#forrootasync-factory)
|
|
23
|
-
- [Configuration Reference](#configuration-reference)
|
|
24
|
-
- [API Endpoints](#api-endpoints)
|
|
25
|
-
- [Entities](#entities)
|
|
26
|
-
- [Recurrence Patterns](#recurrence-patterns)
|
|
27
|
-
- [Participant Status](#participant-status)
|
|
28
|
-
- [Cross-Module Adapter (EVENT_MANAGER_ADAPTER)](#cross-module-adapter-event_manager_adapter)
|
|
29
|
-
- [Exported Services](#exported-services)
|
|
30
|
-
- [Programmatic Usage](#programmatic-usage)
|
|
31
|
-
- [Troubleshooting](#troubleshooting)
|
|
32
|
-
- [License](#license)
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Overview
|
|
37
|
-
|
|
38
|
-
`@flusys/nestjs-event-manager` provides a structured calendar event system with rich recurrence support and per-user participant tracking. The module exposes an `EVENT_MANAGER_ADAPTER` injection token so other modules (Notification, Email) can create events without taking a direct dependency on this package.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## Features
|
|
43
|
-
|
|
44
|
-
- **Calendar events** — Title, description, meeting link, time range, color, all-day flag
|
|
45
|
-
- **Recurrence engine** — NONE, DAILY, WEEKLY, BIWEEKLY, MONTHLY patterns with configurable end dates and day-of-week sets
|
|
46
|
-
- **Participant tracking** — Per-user status: PENDING, ACCEPTED, DECLINED, TENTATIVE
|
|
47
|
-
- **Organizer designation** — Mark specific participants as event organizer
|
|
48
|
-
- **Company scoping** — Optional `companyId`/`branchId` on events
|
|
49
|
-
- **Cross-module adapter** — `EVENT_MANAGER_ADAPTER` token for creating events without circular imports
|
|
50
|
-
- **REQUEST-scoped services** — Dynamic entity resolution per HTTP request
|
|
51
|
-
- **POST-only RPC** — All endpoints use `POST`
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## Compatibility
|
|
56
|
-
|
|
57
|
-
| Package | Version |
|
|
58
|
-
|---------|---------|
|
|
59
|
-
| `@flusys/nestjs-core` | `^4.0.0` |
|
|
60
|
-
| `@flusys/nestjs-shared` | `^4.0.0` |
|
|
61
|
-
| `@nestjs/core` | `^11.0.0` |
|
|
62
|
-
| `typeorm` | `^0.3.0` |
|
|
63
|
-
| Node.js | `>= 18.x` |
|
|
64
7
|
|
|
65
8
|
---
|
|
66
9
|
|
|
@@ -72,304 +15,184 @@ npm install @flusys/nestjs-event-manager @flusys/nestjs-shared @flusys/nestjs-co
|
|
|
72
15
|
|
|
73
16
|
---
|
|
74
17
|
|
|
75
|
-
##
|
|
18
|
+
## 1. Module Registration
|
|
19
|
+
|
|
20
|
+
### forRoot (sync)
|
|
76
21
|
|
|
77
|
-
|
|
22
|
+
#### Mode 1: Single Database
|
|
78
23
|
|
|
79
24
|
```typescript
|
|
80
|
-
import { Module } from '@nestjs/common';
|
|
81
25
|
import { EventManagerModule } from '@flusys/nestjs-event-manager';
|
|
82
26
|
|
|
83
|
-
@Module({
|
|
84
|
-
imports: [
|
|
85
|
-
EventManagerModule.forRoot({
|
|
86
|
-
dataSource: appDataSource, // TypeORM DataSource instance
|
|
87
|
-
enableCompanyFeature: false,
|
|
88
|
-
cacheInstance: hybridCache, // HybridCache instance
|
|
89
|
-
}),
|
|
90
|
-
],
|
|
91
|
-
})
|
|
92
|
-
export class AppModule {}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### With Company Feature
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
27
|
EventManagerModule.forRoot({
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
28
|
+
global: true,
|
|
29
|
+
includeController: true,
|
|
30
|
+
bootstrapAppConfig: {
|
|
31
|
+
databaseMode: 'single',
|
|
32
|
+
enableCompanyFeature: false,
|
|
33
|
+
},
|
|
34
|
+
config: {
|
|
35
|
+
defaultColor: '#3B82F6', // optional, hex color for new events
|
|
36
|
+
maxRecurrenceOccurrences: 365, // optional, cap on expanded occurrences
|
|
37
|
+
defaultDatabaseConfig: {
|
|
38
|
+
type: 'mysql',
|
|
39
|
+
host: process.env.DB_HOST,
|
|
40
|
+
port: Number(process.env.DB_PORT ?? 3306),
|
|
41
|
+
username: process.env.DB_USER,
|
|
42
|
+
password: process.env.DB_PASSWORD,
|
|
43
|
+
database: process.env.DB_NAME,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
103
47
|
```
|
|
104
48
|
|
|
105
|
-
|
|
106
|
-
- `EventController` at `/event-manager/event/*`
|
|
107
|
-
- `EventParticipantController` at `/event-manager/participant/*`
|
|
108
|
-
- `EVENT_MANAGER_ADAPTER` token is available for injection
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## Module Registration
|
|
113
|
-
|
|
114
|
-
### forRoot (Sync)
|
|
49
|
+
#### Mode 2: Multi-Tenant
|
|
115
50
|
|
|
116
51
|
```typescript
|
|
117
52
|
EventManagerModule.forRoot({
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
53
|
+
global: true,
|
|
54
|
+
includeController: true,
|
|
55
|
+
bootstrapAppConfig: {
|
|
56
|
+
databaseMode: 'multi-tenant',
|
|
57
|
+
enableCompanyFeature: true,
|
|
58
|
+
},
|
|
59
|
+
config: {
|
|
60
|
+
defaultColor: '#3B82F6',
|
|
61
|
+
maxRecurrenceOccurrences: 365,
|
|
62
|
+
tenantDefaultDatabaseConfig: {
|
|
63
|
+
type: 'mysql',
|
|
64
|
+
host: process.env.TENANT_DB_HOST,
|
|
65
|
+
port: Number(process.env.TENANT_DB_PORT ?? 3306),
|
|
66
|
+
username: process.env.TENANT_DB_USER,
|
|
67
|
+
password: process.env.TENANT_DB_PASSWORD,
|
|
68
|
+
database: process.env.TENANT_DB_NAME,
|
|
69
|
+
},
|
|
70
|
+
tenants: [
|
|
71
|
+
{ id: 'tenant-a', database: 'tenant_a_db' },
|
|
72
|
+
{ id: 'tenant-b', database: 'tenant_b_db' },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
});
|
|
127
76
|
```
|
|
128
77
|
|
|
129
|
-
### forRootAsync (
|
|
78
|
+
### forRootAsync (factory — recommended)
|
|
130
79
|
|
|
131
80
|
```typescript
|
|
132
|
-
import {
|
|
81
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
82
|
+
import { EventManagerModule, ITenantDatabaseConfig } from '@flusys/nestjs-event-manager';
|
|
133
83
|
|
|
84
|
+
// Single database
|
|
134
85
|
EventManagerModule.forRootAsync({
|
|
86
|
+
global: true,
|
|
87
|
+
bootstrapAppConfig: {
|
|
88
|
+
databaseMode: 'single',
|
|
89
|
+
enableCompanyFeature: true,
|
|
90
|
+
},
|
|
135
91
|
imports: [ConfigModule],
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
92
|
+
useFactory: (cfg: ConfigService) => ({
|
|
93
|
+
defaultColor: cfg.get('EVENT_DEFAULT_COLOR', '#3B82F6'),
|
|
94
|
+
maxRecurrenceOccurrences: cfg.get<number>('EVENT_MAX_RECURRENCE', 365),
|
|
95
|
+
defaultDatabaseConfig: {
|
|
96
|
+
type: 'mysql',
|
|
97
|
+
host: cfg.get('DB_HOST'),
|
|
98
|
+
port: cfg.get<number>('DB_PORT'),
|
|
99
|
+
username: cfg.get('DB_USER'),
|
|
100
|
+
password: cfg.get('DB_PASSWORD'),
|
|
101
|
+
database: cfg.get('DB_NAME'),
|
|
102
|
+
},
|
|
141
103
|
}),
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
**Registered providers:**
|
|
146
|
-
|
|
147
|
-
| Provider | Token | Scope |
|
|
148
|
-
|----------|-------|-------|
|
|
149
|
-
| Module options | `EVENT_MANAGER_MODULE_OPTIONS` | Singleton |
|
|
150
|
-
| `EventManagerConfigService` | class | Singleton |
|
|
151
|
-
| `EventManagerDataSourceProvider` | class | Singleton |
|
|
152
|
-
| `EventService` | class | REQUEST |
|
|
153
|
-
| `EventParticipantService` | class | REQUEST |
|
|
154
|
-
| `EventManagerHelperService` | class | Singleton |
|
|
155
|
-
| `EventManagerAdapter` | `EVENT_MANAGER_ADAPTER` | Singleton |
|
|
156
|
-
|
|
157
|
-
**Exported:** `EventManagerHelperService`, `EVENT_MANAGER_ADAPTER`, `EventManagerConfigService`
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## Configuration Reference
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
interface IEventManagerModuleOptions {
|
|
165
|
-
/** Connected TypeORM DataSource */
|
|
166
|
-
dataSource: DataSource;
|
|
167
|
-
|
|
168
|
-
/** When true, uses company-aware Event entity variant */
|
|
169
|
-
enableCompanyFeature: boolean;
|
|
104
|
+
inject: [ConfigService],
|
|
105
|
+
});
|
|
170
106
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
inject?: any[];
|
|
178
|
-
useFactory: (...args: any[]) => IEventManagerModuleOptions | Promise<IEventManagerModuleOptions>;
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## API Endpoints
|
|
185
|
-
|
|
186
|
-
All endpoints use **POST** and require JWT authentication.
|
|
187
|
-
|
|
188
|
-
### Events — `POST /event-manager/event/*`
|
|
189
|
-
|
|
190
|
-
| Endpoint | Permission | Description |
|
|
191
|
-
|----------|-----------|-------------|
|
|
192
|
-
| `POST /event-manager/event/insert` | `event.create` | Create a new calendar event |
|
|
193
|
-
| `POST /event-manager/event/get-all` | `event.read` | List events with pagination and date filters |
|
|
194
|
-
| `POST /event-manager/event/get/:id` | `event.read` | Get event by ID |
|
|
195
|
-
| `POST /event-manager/event/update` | `event.update` | Update event details |
|
|
196
|
-
| `POST /event-manager/event/delete` | `event.delete` | Delete event (and all participants) |
|
|
197
|
-
| `POST /event-manager/event/get-my-events` | JWT | Get events where current user is a participant |
|
|
198
|
-
| `POST /event-manager/event/get-by-date-range` | `event.read` | Get events within a date range |
|
|
199
|
-
|
|
200
|
-
**Create event request:**
|
|
201
|
-
|
|
202
|
-
```json
|
|
203
|
-
POST /event-manager/event/insert
|
|
204
|
-
{
|
|
205
|
-
"title": "Team Standup",
|
|
206
|
-
"description": "Daily standup meeting",
|
|
207
|
-
"startDate": "2026-03-10T09:00:00Z",
|
|
208
|
-
"endDate": "2026-03-10T09:30:00Z",
|
|
209
|
-
"isAllDay": false,
|
|
210
|
-
"color": "#3B82F6",
|
|
211
|
-
"meetingLink": "https://meet.example.com/standup",
|
|
212
|
-
"recurrence": {
|
|
213
|
-
"type": "DAILY",
|
|
214
|
-
"endDate": "2026-12-31",
|
|
215
|
-
"daysOfWeek": [1, 2, 3, 4, 5]
|
|
107
|
+
// Multi-tenant
|
|
108
|
+
EventManagerModule.forRootAsync({
|
|
109
|
+
global: true,
|
|
110
|
+
bootstrapAppConfig: {
|
|
111
|
+
databaseMode: 'multi-tenant',
|
|
112
|
+
enableCompanyFeature: true,
|
|
216
113
|
},
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
114
|
+
imports: [ConfigModule],
|
|
115
|
+
useFactory: (cfg: ConfigService) => ({
|
|
116
|
+
defaultColor: cfg.get('EVENT_DEFAULT_COLOR', '#3B82F6'),
|
|
117
|
+
maxRecurrenceOccurrences: cfg.get<number>('EVENT_MAX_RECURRENCE', 365),
|
|
118
|
+
tenantDefaultDatabaseConfig: {
|
|
119
|
+
type: 'mysql',
|
|
120
|
+
host: cfg.get('TENANT_DB_HOST'),
|
|
121
|
+
port: cfg.get<number>('TENANT_DB_PORT'),
|
|
122
|
+
username: cfg.get('TENANT_DB_USER'),
|
|
123
|
+
password: cfg.get('TENANT_DB_PASSWORD'),
|
|
124
|
+
database: cfg.get('TENANT_DB_NAME'),
|
|
125
|
+
},
|
|
126
|
+
tenants: cfg.get<ITenantDatabaseConfig[]>('TENANTS'),
|
|
127
|
+
}),
|
|
128
|
+
inject: [ConfigService],
|
|
129
|
+
});
|
|
222
130
|
```
|
|
223
131
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
| Endpoint | Permission | Description |
|
|
227
|
-
|----------|-----------|-------------|
|
|
228
|
-
| `POST /event-manager/participant/insert` | `event.update` | Add participant to event |
|
|
229
|
-
| `POST /event-manager/participant/get-all` | `event.read` | List participants for an event |
|
|
230
|
-
| `POST /event-manager/participant/update-status` | JWT | Update own participation status |
|
|
231
|
-
| `POST /event-manager/participant/delete` | `event.update` | Remove participant from event |
|
|
232
|
-
|
|
233
|
-
**Update status request:**
|
|
234
|
-
|
|
235
|
-
```json
|
|
236
|
-
POST /event-manager/participant/update-status
|
|
237
|
-
{
|
|
238
|
-
"eventId": "uuid",
|
|
239
|
-
"status": "ACCEPTED"
|
|
240
|
-
}
|
|
241
|
-
```
|
|
132
|
+
**Exported services** (available for injection after registration):
|
|
133
|
+
`EventService`, `EventManagerHelperService`, `EventManagerConfigService`, `EventManagerDataSourceProvider`, `EVENT_MANAGER_ADAPTER`
|
|
242
134
|
|
|
243
135
|
---
|
|
244
136
|
|
|
245
|
-
## Entities
|
|
246
|
-
|
|
247
|
-
### Core Entities
|
|
248
|
-
|
|
249
|
-
| Entity | Table | Description |
|
|
250
|
-
|--------|-------|-------------|
|
|
251
|
-
| `Event` | `event_manager_event` | Calendar event with recurrence config |
|
|
252
|
-
| `EventParticipant` | `event_manager_participant` | User participation with status |
|
|
253
|
-
|
|
254
|
-
### Company Feature Entities (`enableCompanyFeature: true`)
|
|
255
|
-
|
|
256
|
-
| Entity | Table | Description |
|
|
257
|
-
|--------|-------|-------------|
|
|
258
|
-
| `EventWithCompany` | `event_manager_event` | Same as Event + `companyId` and `branchId` |
|
|
137
|
+
## 2. Entities
|
|
259
138
|
|
|
260
139
|
```typescript
|
|
261
|
-
import {
|
|
140
|
+
import { getEventManagerEntitiesByConfig } from '@flusys/nestjs-event-manager/entities';
|
|
262
141
|
|
|
263
142
|
TypeOrmModule.forRoot({
|
|
264
143
|
entities: [
|
|
265
|
-
...
|
|
144
|
+
...getEventManagerEntitiesByConfig(false), // match enableCompanyFeature in bootstrapAppConfig
|
|
266
145
|
],
|
|
267
|
-
})
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
## Recurrence Patterns
|
|
273
|
-
|
|
274
|
-
| Type | Description |
|
|
275
|
-
|------|-------------|
|
|
276
|
-
| `NONE` | Single occurrence, no recurrence |
|
|
277
|
-
| `DAILY` | Repeats every day (or specific days via `daysOfWeek`) |
|
|
278
|
-
| `WEEKLY` | Repeats every week on the same day |
|
|
279
|
-
| `BIWEEKLY` | Repeats every two weeks |
|
|
280
|
-
| `MONTHLY` | Repeats on the same day of month |
|
|
281
|
-
|
|
282
|
-
**Recurrence configuration:**
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
interface IRecurrenceConfig {
|
|
286
|
-
type: 'NONE' | 'DAILY' | 'WEEKLY' | 'BIWEEKLY' | 'MONTHLY';
|
|
287
|
-
endDate?: string; // ISO date — when recurrence stops
|
|
288
|
-
daysOfWeek?: number[]; // 0=Sunday, 1=Monday, ... 6=Saturday (for DAILY/WEEKLY)
|
|
289
|
-
interval?: number; // Custom interval (e.g., every 3 weeks)
|
|
290
|
-
}
|
|
146
|
+
});
|
|
291
147
|
```
|
|
292
148
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
149
|
+
| `enableCompanyFeature` | Entities registered |
|
|
150
|
+
| ---------------------- | -------------------------------------- |
|
|
151
|
+
| `false` | `Event`, `EventParticipant` |
|
|
152
|
+
| `true` | `EventWithCompany`, `EventParticipant` |
|
|
296
153
|
|
|
297
|
-
|
|
298
|
-
|--------|-------------|
|
|
299
|
-
| `PENDING` | Invited but not responded |
|
|
300
|
-
| `ACCEPTED` | Confirmed attendance |
|
|
301
|
-
| `DECLINED` | Declined invitation |
|
|
302
|
-
| `TENTATIVE` | Tentatively attending |
|
|
303
|
-
|
|
304
|
-
Participants update their own status via `POST /event-manager/participant/update-status`.
|
|
154
|
+
The service resolves the correct entity variant automatically per request.
|
|
305
155
|
|
|
306
156
|
---
|
|
307
157
|
|
|
308
|
-
## Cross-Module Adapter (EVENT_MANAGER_ADAPTER)
|
|
309
|
-
|
|
310
|
-
The adapter allows other modules to create and manage events without importing `@flusys/nestjs-event-manager` directly. This prevents circular dependencies.
|
|
311
|
-
|
|
312
|
-
**The interface is defined in `@flusys/nestjs-shared`:**
|
|
158
|
+
## 4. Cross-Module Adapter (EVENT_MANAGER_ADAPTER)
|
|
313
159
|
|
|
314
|
-
|
|
315
|
-
import { IEventManagerAdapter, EVENT_MANAGER_ADAPTER } from '@flusys/nestjs-shared/interfaces';
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
**Using the adapter in another module:**
|
|
160
|
+
Other modules can create events without importing this package directly. The `IEventManagerAdapter` interface and `EVENT_MANAGER_ADAPTER` token are defined in `@flusys/nestjs-shared`.
|
|
319
161
|
|
|
320
162
|
```typescript
|
|
321
|
-
import { IEventManagerAdapter } from '@flusys/nestjs-shared
|
|
322
|
-
import {
|
|
163
|
+
import { IEventManagerAdapter, EVENT_MANAGER_ADAPTER } from '@flusys/nestjs-shared';
|
|
164
|
+
import { Optional } from '@nestjs/common';
|
|
323
165
|
|
|
324
166
|
@Injectable()
|
|
325
|
-
export class
|
|
167
|
+
export class NotificationService {
|
|
326
168
|
constructor(
|
|
327
|
-
@Optional()
|
|
169
|
+
@Optional()
|
|
170
|
+
@Inject(EVENT_MANAGER_ADAPTER)
|
|
328
171
|
private readonly eventAdapter?: IEventManagerAdapter,
|
|
329
172
|
) {}
|
|
330
173
|
|
|
331
|
-
async
|
|
174
|
+
async scheduleReminder(userId: string, date: string): Promise<void> {
|
|
332
175
|
await this.eventAdapter?.createEvent({
|
|
333
|
-
title:
|
|
334
|
-
|
|
335
|
-
|
|
176
|
+
title: 'Reminder',
|
|
177
|
+
eventDate: date,
|
|
178
|
+
startTime: '09:00',
|
|
179
|
+
endTime: '09:30',
|
|
180
|
+
participantIds: [userId],
|
|
181
|
+
organizerId: userId,
|
|
336
182
|
});
|
|
337
183
|
}
|
|
338
184
|
}
|
|
339
185
|
```
|
|
340
186
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
**IEventManagerAdapter interface:**
|
|
344
|
-
|
|
345
|
-
```typescript
|
|
346
|
-
interface IEventManagerAdapter {
|
|
347
|
-
createEvent(data: ICreateEventData): Promise<{ id: string }>;
|
|
348
|
-
updateEvent(id: string, data: Partial<ICreateEventData>): Promise<void>;
|
|
349
|
-
deleteEvent(id: string): Promise<void>;
|
|
350
|
-
addParticipant(eventId: string, userId: string): Promise<void>;
|
|
351
|
-
removeParticipant(eventId: string, userId: string): Promise<void>;
|
|
352
|
-
updateParticipantStatus(eventId: string, userId: string, status: ParticipantStatus): Promise<void>;
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
---
|
|
187
|
+
The adapter exposes: `createEvent`, `updateParticipantStatus`, `getEventsForUser`, `getEventById`.
|
|
357
188
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
| Service | Description |
|
|
361
|
-
|---------|-------------|
|
|
362
|
-
| `EventManagerHelperService` | Singleton service for programmatic event management from other modules |
|
|
363
|
-
| `EventService` | Full event CRUD (REQUEST-scoped) |
|
|
364
|
-
| `EventParticipantService` | Participant management (REQUEST-scoped) |
|
|
365
|
-
| `EventManagerConfigService` | Exposes runtime config |
|
|
366
|
-
| `EVENT_MANAGER_ADAPTER` | Cross-module adapter token |
|
|
189
|
+
Using `@Optional()` means your module works even when `EventManagerModule` is not registered.
|
|
367
190
|
|
|
368
191
|
---
|
|
369
192
|
|
|
370
|
-
## Programmatic Usage
|
|
193
|
+
## 5. Programmatic Usage (singleton)
|
|
371
194
|
|
|
372
|
-
Use `EventManagerHelperService` (
|
|
195
|
+
Use `EventManagerHelperService` (not REQUEST-scoped) for programmatic event creation from background jobs or other singleton services:
|
|
373
196
|
|
|
374
197
|
```typescript
|
|
375
198
|
import { EventManagerHelperService } from '@flusys/nestjs-event-manager';
|
|
@@ -381,15 +204,13 @@ export class OnboardingService {
|
|
|
381
204
|
private readonly eventHelper: EventManagerHelperService,
|
|
382
205
|
) {}
|
|
383
206
|
|
|
384
|
-
async
|
|
385
|
-
const nextWeek = new Date();
|
|
386
|
-
nextWeek.setDate(nextWeek.getDate() + 7);
|
|
387
|
-
|
|
207
|
+
async scheduleCall(userId: string): Promise<void> {
|
|
388
208
|
await this.eventHelper.createEvent({
|
|
389
209
|
title: 'Onboarding Call',
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
210
|
+
eventDate: '2026-05-01',
|
|
211
|
+
startTime: '10:00',
|
|
212
|
+
endTime: '10:30',
|
|
213
|
+
organizerId: userId,
|
|
393
214
|
});
|
|
394
215
|
}
|
|
395
216
|
}
|
|
@@ -397,39 +218,7 @@ export class OnboardingService {
|
|
|
397
218
|
|
|
398
219
|
---
|
|
399
220
|
|
|
400
|
-
## Troubleshooting
|
|
401
|
-
|
|
402
|
-
**`EVENT_MANAGER_ADAPTER` is undefined**
|
|
403
|
-
|
|
404
|
-
`EventManagerModule` was not registered in the application module. Either register it or use `@Optional()` in the consuming service.
|
|
405
|
-
|
|
406
|
-
---
|
|
407
|
-
|
|
408
|
-
**Events not filtered by company**
|
|
409
|
-
|
|
410
|
-
Ensure `enableCompanyFeature: true` is set and the JWT contains `companyId`. Without the company ID in the token, company-scoped queries return all events.
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
**Recurrence events not expanding**
|
|
415
|
-
|
|
416
|
-
`nestjs-event-manager` stores the recurrence configuration as a JSON column — it does not auto-expand recurring events into separate database rows. Your frontend or a separate expansion service is responsible for generating occurrences from the recurrence config.
|
|
417
|
-
|
|
418
|
-
---
|
|
419
|
-
|
|
420
|
-
**`No metadata for entity`**
|
|
421
|
-
|
|
422
|
-
Register entities in TypeORM:
|
|
423
|
-
```typescript
|
|
424
|
-
entities: [...EventManagerModule.getEntities({ enableCompanyFeature: true })]
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
---
|
|
428
221
|
|
|
429
222
|
## License
|
|
430
223
|
|
|
431
224
|
MIT © FLUSYS
|
|
432
|
-
|
|
433
|
-
---
|
|
434
|
-
|
|
435
|
-
> Part of the **FLUSYS** framework — a full-stack monorepo powering Angular 21 + NestJS 11 applications.
|
|
@@ -4,8 +4,6 @@ export declare class EventManagerAdapter implements IEventManagerAdapter {
|
|
|
4
4
|
private readonly eventManagerHelper;
|
|
5
5
|
constructor(eventManagerHelper: EventManagerHelperService);
|
|
6
6
|
createEvent(options: CreateEventOptions): Promise<EventResult>;
|
|
7
|
-
addParticipants(eventId: string, userIds: string[], companyId?: string): Promise<void>;
|
|
8
|
-
removeParticipant(eventId: string, userId: string): Promise<void>;
|
|
9
7
|
updateParticipantStatus(participantId: string, status: ParticipantStatus): Promise<void>;
|
|
10
8
|
getEventsForUser(userId: string, startDate: Date, endDate: Date, companyId?: string): Promise<EventResult[]>;
|
|
11
9
|
getEventById(eventId: string): Promise<EventResult | null>;
|
|
@@ -41,17 +41,11 @@ let EventManagerAdapter = class EventManagerAdapter {
|
|
|
41
41
|
async createEvent(options) {
|
|
42
42
|
return this.eventManagerHelper.createEvent(options);
|
|
43
43
|
}
|
|
44
|
-
async addParticipants(eventId, userIds, companyId) {
|
|
45
|
-
await this.eventManagerHelper.addParticipants(eventId, userIds, companyId);
|
|
46
|
-
}
|
|
47
|
-
async removeParticipant(eventId, userId) {
|
|
48
|
-
await this.eventManagerHelper.removeParticipant(eventId, userId);
|
|
49
|
-
}
|
|
50
44
|
async updateParticipantStatus(participantId, status) {
|
|
51
45
|
await this.eventManagerHelper.updateParticipantStatus(participantId, status);
|
|
52
46
|
}
|
|
53
47
|
async getEventsForUser(userId, startDate, endDate, companyId) {
|
|
54
|
-
return this.eventManagerHelper.getEventsForUser(userId, startDate, endDate, companyId);
|
|
48
|
+
return this.eventManagerHelper.getEventsForUser(userId, startDate.toISOString().split('T')[0], endDate.toISOString().split('T')[0], companyId);
|
|
55
49
|
}
|
|
56
50
|
async getEventById(eventId) {
|
|
57
51
|
return this.eventManagerHelper.getEventById(eventId);
|
|
@@ -10,9 +10,6 @@ function _export(target, all) {
|
|
|
10
10
|
});
|
|
11
11
|
}
|
|
12
12
|
_export(exports, {
|
|
13
|
-
get EVENT_MANAGER_MODULE_MESSAGES () {
|
|
14
|
-
return EVENT_MANAGER_MODULE_MESSAGES;
|
|
15
|
-
},
|
|
16
13
|
get EVENT_MESSAGES () {
|
|
17
14
|
return EVENT_MESSAGES;
|
|
18
15
|
},
|
|
@@ -21,37 +18,10 @@ _export(exports, {
|
|
|
21
18
|
}
|
|
22
19
|
});
|
|
23
20
|
const EVENT_MESSAGES = {
|
|
24
|
-
CREATE_SUCCESS: 'event.create.success',
|
|
25
|
-
CREATE_MANY_SUCCESS: 'event.create.many.success',
|
|
26
|
-
GET_SUCCESS: 'event.get.success',
|
|
27
21
|
GET_ALL_SUCCESS: 'event.get.all.success',
|
|
28
|
-
|
|
29
|
-
UPDATE_MANY_SUCCESS: 'event.update.many.success',
|
|
30
|
-
DELETE_SUCCESS: 'event.delete.success',
|
|
31
|
-
RESTORE_SUCCESS: 'event.restore.success',
|
|
32
|
-
NOT_FOUND: 'event.not.found',
|
|
33
|
-
PUBLISH_SUCCESS: 'event.publish.success',
|
|
34
|
-
UNPUBLISH_SUCCESS: 'event.unpublish.success',
|
|
35
|
-
CANCEL_SUCCESS: 'event.cancel.success',
|
|
36
|
-
UPCOMING_SUCCESS: 'event.upcoming.success',
|
|
37
|
-
MY_EVENTS_SUCCESS: 'event.my.events.success'
|
|
22
|
+
NOT_FOUND: 'event.not.found'
|
|
38
23
|
};
|
|
39
24
|
const EVENT_PARTICIPANT_MESSAGES = {
|
|
40
|
-
CREATE_SUCCESS: 'event.participant.create.success',
|
|
41
|
-
CREATE_MANY_SUCCESS: 'event.participant.create.many.success',
|
|
42
|
-
GET_SUCCESS: 'event.participant.get.success',
|
|
43
|
-
GET_ALL_SUCCESS: 'event.participant.get.all.success',
|
|
44
|
-
UPDATE_SUCCESS: 'event.participant.update.success',
|
|
45
|
-
UPDATE_MANY_SUCCESS: 'event.participant.update.many.success',
|
|
46
|
-
DELETE_SUCCESS: 'event.participant.delete.success',
|
|
47
|
-
RESTORE_SUCCESS: 'event.participant.restore.success',
|
|
48
25
|
NOT_FOUND: 'event.participant.not.found',
|
|
49
|
-
REGISTER_SUCCESS: 'event.participant.register.success',
|
|
50
|
-
UNREGISTER_SUCCESS: 'event.participant.unregister.success',
|
|
51
|
-
CHECKIN_SUCCESS: 'event.participant.checkin.success',
|
|
52
26
|
STATUS_UPDATE_SUCCESS: 'event.participant.status.update.success'
|
|
53
27
|
};
|
|
54
|
-
const EVENT_MANAGER_MODULE_MESSAGES = {
|
|
55
|
-
EVENT: EVENT_MESSAGES,
|
|
56
|
-
EVENT_PARTICIPANT: EVENT_PARTICIPANT_MESSAGES
|
|
57
|
-
};
|