@hed-hog/core 0.0.350 → 0.0.353
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/dist/access-log/access-log.controller.d.ts +16 -0
- package/dist/access-log/access-log.controller.d.ts.map +1 -0
- package/dist/access-log/access-log.controller.js +44 -0
- package/dist/access-log/access-log.controller.js.map +1 -0
- package/dist/access-log/access-log.interceptor.d.ts +9 -0
- package/dist/access-log/access-log.interceptor.d.ts.map +1 -0
- package/dist/access-log/access-log.interceptor.js +46 -0
- package/dist/access-log/access-log.interceptor.js.map +1 -0
- package/dist/access-log/access-log.module.d.ts +3 -0
- package/dist/access-log/access-log.module.d.ts.map +1 -0
- package/dist/access-log/access-log.module.js +29 -0
- package/dist/access-log/access-log.module.js.map +1 -0
- package/dist/access-log/access-log.service.d.ts +47 -0
- package/dist/access-log/access-log.service.d.ts.map +1 -0
- package/dist/access-log/access-log.service.js +113 -0
- package/dist/access-log/access-log.service.js.map +1 -0
- package/dist/access-log/dto/query-access-log.dto.d.ts +8 -0
- package/dist/access-log/dto/query-access-log.dto.d.ts.map +1 -0
- package/dist/access-log/dto/query-access-log.dto.js +42 -0
- package/dist/access-log/dto/query-access-log.dto.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +9 -9
- package/dist/auth/auth.service.d.ts +19 -19
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +0 -4
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +2 -2
- package/dist/challenge/challenge.service.d.ts.map +1 -1
- package/dist/challenge/challenge.service.js +0 -1
- package/dist/challenge/challenge.service.js.map +1 -1
- package/dist/core/system.module.d.ts.map +1 -1
- package/dist/core/system.module.js +1 -0
- package/dist/core/system.module.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +12 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
- package/dist/dashboard/dashboard.module.d.ts.map +1 -1
- package/dist/dashboard/dashboard.module.js +4 -1
- package/dist/dashboard/dashboard.module.js.map +1 -1
- package/dist/file/file.controller.js +0 -1
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +65 -0
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +151 -3
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/abstract.provider.d.ts +8 -0
- package/dist/file/provider/abstract.provider.d.ts.map +1 -1
- package/dist/file/provider/abstract.provider.js.map +1 -1
- package/dist/file/provider/azure.provider.d.ts +4 -0
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +14 -0
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts +4 -0
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +14 -0
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts +4 -0
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +19 -0
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/provider.factory.d.ts.map +1 -1
- package/dist/file/provider/provider.factory.js +3 -0
- package/dist/file/provider/provider.factory.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts +4 -0
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +17 -0
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/mcp/mcp-audit.service.d.ts +3 -1
- package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
- package/dist/mcp/mcp-audit.service.js +14 -2
- package/dist/mcp/mcp-audit.service.js.map +1 -1
- package/dist/mcp/mcp.controller.d.ts +3 -1
- package/dist/mcp/mcp.controller.d.ts.map +1 -1
- package/dist/mcp/mcp.controller.js +10 -2
- package/dist/mcp/mcp.controller.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +72 -0
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp/tools/core-ai.mcp-tools.d.ts +45 -0
- package/dist/mcp/tools/core-ai.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-ai.mcp-tools.js +214 -0
- package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts +21 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +89 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts +29 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.js +149 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts +30 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +185 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-files.mcp-tools.d.ts +26 -0
- package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-files.mcp-tools.js +140 -0
- package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts +26 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.js +168 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +32 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js +178 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts +14 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js +106 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail.mcp-tools.d.ts +36 -0
- package/dist/mcp/tools/core-mail.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail.mcp-tools.js +184 -0
- package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts +21 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.js +118 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts +40 -0
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-menus.mcp-tools.js +268 -0
- package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts +31 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.js +178 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-profile.mcp-tools.d.ts +20 -0
- package/dist/mcp/tools/core-profile.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-profile.mcp-tools.js +111 -0
- package/dist/mcp/tools/core-profile.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts +70 -0
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-roles.mcp-tools.js +355 -0
- package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts +52 -0
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-routes.mcp-tools.js +254 -0
- package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts +47 -0
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-screens.mcp-tools.js +250 -0
- package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts +20 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.js +128 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts +25 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-settings.mcp-tools.js +138 -0
- package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-system.mcp-tools.d.ts +8 -0
- package/dist/mcp/tools/core-system.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-system.mcp-tools.js +40 -0
- package/dist/mcp/tools/core-system.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts +46 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.js +266 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts +25 -2
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +666 -36
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/notification/notification.controller.d.ts +8 -4
- package/dist/notification/notification.controller.d.ts.map +1 -1
- package/dist/notification/notification.controller.js +12 -0
- package/dist/notification/notification.controller.js.map +1 -1
- package/dist/notification/notification.service.d.ts +19 -5
- package/dist/notification/notification.service.d.ts.map +1 -1
- package/dist/notification/notification.service.js +155 -9
- package/dist/notification/notification.service.js.map +1 -1
- package/dist/pdf/pdf.service.js +1 -1
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +3 -3
- package/dist/profile/profile.controller.js +0 -1
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/profile/profile.module.d.ts.map +1 -1
- package/dist/profile/profile.module.js +1 -0
- package/dist/profile/profile.module.js.map +1 -1
- package/dist/profile/profile.service.d.ts +3 -3
- package/dist/session/session.controller.d.ts +2 -2
- package/dist/session/session.service.d.ts +6 -6
- package/dist/setting/setting.controller.d.ts +1 -1
- package/dist/setting/setting.service.d.ts +1 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +1 -4
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/task/task.service.d.ts +1 -0
- package/dist/task/task.service.d.ts.map +1 -1
- package/dist/task/task.service.js +25 -0
- package/dist/task/task.service.js.map +1 -1
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +0 -1
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +9 -9
- package/dist/user/user.service.d.ts +21 -21
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts +22 -0
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -0
- package/dist/webhook-integration/dto/webhook-action.dto.js +120 -0
- package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +7 -5
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +18 -5
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +14 -5
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +174 -41
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/hedhog/data/menu.yaml +15 -0
- package/hedhog/data/route.yaml +1304 -0
- package/hedhog/data/setting_group.yaml +67 -0
- package/hedhog/data/setting_subgroup.yaml +16 -0
- package/hedhog/frontend/app/access-log/page.tsx.ejs +772 -0
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +10 -3
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +33 -13
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +12 -5
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +12 -5
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +1817 -356
- package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +43 -5
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +35 -7
- package/hedhog/frontend/app/menu/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/roles/page.tsx.ejs +18 -6
- package/hedhog/frontend/app/routes/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +344 -171
- package/hedhog/frontend/app/users/user-access-sheet.tsx.ejs +310 -304
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +25 -7
- package/hedhog/frontend/messages/en.json +104 -3
- package/hedhog/frontend/messages/pt.json +104 -3
- package/hedhog/table/access_log.yaml +31 -0
- package/package.json +4 -3
- package/src/access-log/access-log.controller.ts +29 -0
- package/src/access-log/access-log.interceptor.ts +38 -0
- package/src/access-log/access-log.module.ts +16 -0
- package/src/access-log/access-log.service.ts +129 -0
- package/src/access-log/dto/query-access-log.dto.ts +23 -0
- package/src/auth/auth.service.ts +0 -7
- package/src/challenge/challenge.service.ts +0 -2
- package/src/core/system.module.ts +1 -0
- package/src/core.module.ts +12 -0
- package/src/dashboard/dashboard.module.ts +4 -1
- package/src/file/file.controller.ts +14 -14
- package/src/file/file.service.ts +198 -4
- package/src/file/provider/abstract.provider.ts +10 -0
- package/src/file/provider/azure.provider.ts +24 -0
- package/src/file/provider/gcs.provider.ts +20 -0
- package/src/file/provider/local.provider.ts +30 -2
- package/src/file/provider/provider.factory.ts +3 -0
- package/src/file/provider/s3.provider.ts +22 -0
- package/src/mcp/mcp-audit.service.ts +47 -36
- package/src/mcp/mcp.controller.ts +40 -30
- package/src/mcp/mcp.module.ts +72 -0
- package/src/mcp/tools/core-ai.mcp-tools.ts +156 -0
- package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +63 -0
- package/src/mcp/tools/core-dashboard.mcp-tools.ts +103 -0
- package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +134 -0
- package/src/mcp/tools/core-files.mcp-tools.ts +105 -0
- package/src/mcp/tools/core-integration-events.mcp-tools.ts +118 -0
- package/src/mcp/tools/core-mail-profile.mcp-tools.ts +128 -0
- package/src/mcp/tools/core-mail-sent.mcp-tools.ts +76 -0
- package/src/mcp/tools/core-mail.mcp-tools.ts +130 -0
- package/src/mcp/tools/core-mcp-chat.mcp-tools.ts +81 -0
- package/src/mcp/tools/core-menus.mcp-tools.ts +197 -0
- package/src/mcp/tools/core-notifications.mcp-tools.ts +128 -0
- package/src/mcp/tools/core-profile.mcp-tools.ts +74 -0
- package/src/mcp/tools/core-roles.mcp-tools.ts +288 -0
- package/src/mcp/tools/core-routes.mcp-tools.ts +196 -0
- package/src/mcp/tools/core-screens.mcp-tools.ts +186 -0
- package/src/mcp/tools/core-sessions.mcp-tools.ts +97 -0
- package/src/mcp/tools/core-settings.mcp-tools.ts +171 -53
- package/src/mcp/tools/core-system.mcp-tools.ts +19 -0
- package/src/mcp/tools/core-webhooks.mcp-tools.ts +199 -0
- package/src/mcp-chat/mcp-chat.service.ts +887 -38
- package/src/notification/notification.controller.ts +20 -8
- package/src/notification/notification.service.ts +209 -9
- package/src/pdf/pdf.service.ts +1 -1
- package/src/profile/profile.controller.ts +1 -1
- package/src/profile/profile.module.ts +1 -0
- package/src/setting/setting.service.ts +8 -11
- package/src/task/task.service.ts +31 -0
- package/src/token/token.service.ts +0 -2
- package/src/webhook-integration/dto/webhook-action.dto.ts +96 -0
- package/src/webhook-integration/webhook-integration.controller.ts +124 -103
- package/src/webhook-integration/webhook-integration.service.ts +267 -64
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Role, User } from '@hed-hog/api';
|
|
2
2
|
import { Pagination } from '@hed-hog/api-pagination';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
Body,
|
|
5
|
+
Controller,
|
|
6
|
+
Delete,
|
|
7
|
+
Get,
|
|
8
|
+
Param,
|
|
9
|
+
ParseIntPipe,
|
|
10
|
+
Patch,
|
|
11
|
+
Post,
|
|
12
|
+
Req,
|
|
13
|
+
Res,
|
|
12
14
|
} from '@nestjs/common';
|
|
15
|
+
import type { Request, Response } from 'express';
|
|
13
16
|
import { CreateNotificationDto } from './dto/create-notification.dto';
|
|
14
17
|
import { UpdateProgressDto } from './dto/update-progress.dto';
|
|
15
18
|
import { NotificationService } from './notification.service';
|
|
@@ -24,6 +27,15 @@ export class NotificationController {
|
|
|
24
27
|
return this.notificationService.list(id, paginationParams);
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
@Get('stream')
|
|
31
|
+
async stream(
|
|
32
|
+
@User() { id },
|
|
33
|
+
@Req() req: Request,
|
|
34
|
+
@Res() res: Response,
|
|
35
|
+
) {
|
|
36
|
+
return this.notificationService.stream(id, req, res);
|
|
37
|
+
}
|
|
38
|
+
|
|
27
39
|
@Get('unread-count')
|
|
28
40
|
async unreadCount(@User() { id }) {
|
|
29
41
|
return this.notificationService.unreadCount(id);
|
|
@@ -5,19 +5,92 @@ import {
|
|
|
5
5
|
forwardRef,
|
|
6
6
|
Inject,
|
|
7
7
|
Injectable,
|
|
8
|
+
Logger,
|
|
8
9
|
NotFoundException,
|
|
10
|
+
OnModuleDestroy,
|
|
11
|
+
OnModuleInit,
|
|
9
12
|
} from '@nestjs/common';
|
|
13
|
+
import type { Request, Response } from 'express';
|
|
14
|
+
import { randomUUID } from 'node:crypto';
|
|
15
|
+
import { EventEmitter } from 'node:events';
|
|
16
|
+
import { Client, type Notification as PgNotification } from 'pg';
|
|
10
17
|
import { CreateNotificationDto } from './dto/create-notification.dto';
|
|
11
18
|
import { UpdateProgressDto } from './dto/update-progress.dto';
|
|
12
19
|
|
|
20
|
+
type NotificationStreamEventType =
|
|
21
|
+
| 'ready'
|
|
22
|
+
| 'notification.created'
|
|
23
|
+
| 'notification.updated';
|
|
24
|
+
|
|
25
|
+
type NotificationStreamEvent = {
|
|
26
|
+
type: NotificationStreamEventType;
|
|
27
|
+
notificationId?: number;
|
|
28
|
+
notification?: unknown;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type ClusterNotificationPayload = NotificationStreamEvent & {
|
|
32
|
+
userId: number;
|
|
33
|
+
originInstanceId: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
13
36
|
@Injectable()
|
|
14
|
-
export class NotificationService {
|
|
37
|
+
export class NotificationService implements OnModuleInit, OnModuleDestroy {
|
|
38
|
+
private readonly logger = new Logger(NotificationService.name);
|
|
39
|
+
private readonly notificationEvents = new EventEmitter();
|
|
40
|
+
private readonly instanceId = randomUUID();
|
|
41
|
+
private readonly channelName = 'notification_events';
|
|
42
|
+
private pgClient: Client | null = null;
|
|
43
|
+
|
|
15
44
|
constructor(
|
|
16
45
|
@Inject(forwardRef(() => PrismaService))
|
|
17
46
|
private readonly prisma: PrismaService,
|
|
18
47
|
@Inject(forwardRef(() => PaginationService))
|
|
19
48
|
private readonly pagination: PaginationService,
|
|
20
|
-
) {
|
|
49
|
+
) {
|
|
50
|
+
this.notificationEvents.setMaxListeners(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async onModuleInit() {
|
|
54
|
+
const databaseUrl = String(process.env.DATABASE_URL || '');
|
|
55
|
+
if (!databaseUrl.startsWith('postgresql://')) {
|
|
56
|
+
this.logger.warn(
|
|
57
|
+
'Cluster notification stream disabled because DATABASE_URL is not PostgreSQL',
|
|
58
|
+
);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.pgClient = new Client({ connectionString: databaseUrl });
|
|
63
|
+
this.pgClient.on('notification', (message: PgNotification) => {
|
|
64
|
+
this.handleClusterNotification(message);
|
|
65
|
+
});
|
|
66
|
+
this.pgClient.on('error', (error) => {
|
|
67
|
+
this.logger.error('Cluster notification listener error', error);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await this.pgClient.connect();
|
|
71
|
+
await this.pgClient.query(`LISTEN ${this.channelName}`);
|
|
72
|
+
this.logger.log(
|
|
73
|
+
`Cluster notification listener ready on channel ${this.channelName}`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async onModuleDestroy() {
|
|
78
|
+
if (!this.pgClient) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await this.pgClient.query(`UNLISTEN ${this.channelName}`);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
this.logger.warn('Failed to unlisten notification channel', error as any);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await this.pgClient.end();
|
|
90
|
+
} finally {
|
|
91
|
+
this.pgClient = null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
21
94
|
|
|
22
95
|
async list(userId: number, paginationParams: any) {
|
|
23
96
|
return this.pagination.paginate(
|
|
@@ -40,35 +113,56 @@ export class NotificationService {
|
|
|
40
113
|
async markRead(userId: number, id: number) {
|
|
41
114
|
const notification = await this.assertOwnership(userId, id);
|
|
42
115
|
if (notification.auto_remove) {
|
|
43
|
-
|
|
116
|
+
const deleted = await this.prisma.notification.delete({ where: { id } });
|
|
117
|
+
await this.broadcastNotificationEvent(userId, {
|
|
118
|
+
type: 'notification.updated',
|
|
119
|
+
notificationId: id,
|
|
120
|
+
});
|
|
121
|
+
return deleted;
|
|
44
122
|
}
|
|
45
|
-
|
|
123
|
+
const updated = await this.prisma.notification.update({
|
|
46
124
|
where: { id },
|
|
47
125
|
data: { status: 'read' },
|
|
48
126
|
});
|
|
127
|
+
await this.broadcastNotificationEvent(userId, {
|
|
128
|
+
type: 'notification.updated',
|
|
129
|
+
notificationId: id,
|
|
130
|
+
});
|
|
131
|
+
return updated;
|
|
49
132
|
}
|
|
50
133
|
|
|
51
134
|
async markAllRead(userId: number) {
|
|
52
135
|
await this.prisma.notification.deleteMany({
|
|
53
136
|
where: { user_id: userId, status: 'unread', auto_remove: true },
|
|
54
137
|
});
|
|
55
|
-
|
|
138
|
+
const updated = await this.prisma.notification.updateMany({
|
|
56
139
|
where: { user_id: userId, status: 'unread' },
|
|
57
140
|
data: { status: 'read' },
|
|
58
141
|
});
|
|
142
|
+
await this.broadcastNotificationEvent(userId, { type: 'notification.updated' });
|
|
143
|
+
return updated;
|
|
59
144
|
}
|
|
60
145
|
|
|
61
146
|
async delete(userId: number, id: number) {
|
|
62
147
|
await this.assertOwnership(userId, id);
|
|
63
|
-
|
|
148
|
+
const deleted = await this.prisma.notification.delete({ where: { id } });
|
|
149
|
+
await this.broadcastNotificationEvent(userId, {
|
|
150
|
+
type: 'notification.updated',
|
|
151
|
+
notificationId: id,
|
|
152
|
+
});
|
|
153
|
+
return deleted;
|
|
64
154
|
}
|
|
65
155
|
|
|
66
156
|
async deleteAll(userId: number) {
|
|
67
|
-
|
|
157
|
+
const result = await this.prisma.notification.deleteMany({
|
|
158
|
+
where: { user_id: userId },
|
|
159
|
+
});
|
|
160
|
+
await this.broadcastNotificationEvent(userId, { type: 'notification.updated' });
|
|
161
|
+
return result;
|
|
68
162
|
}
|
|
69
163
|
|
|
70
164
|
async create(data: CreateNotificationDto) {
|
|
71
|
-
|
|
165
|
+
const notification = await this.prisma.notification.create({
|
|
72
166
|
data: {
|
|
73
167
|
user_id: data.user_id,
|
|
74
168
|
title: data.title,
|
|
@@ -83,12 +177,18 @@ export class NotificationService {
|
|
|
83
177
|
started_at: data.started_at ? new Date(data.started_at) : undefined,
|
|
84
178
|
},
|
|
85
179
|
});
|
|
180
|
+
await this.broadcastNotificationEvent(data.user_id, {
|
|
181
|
+
type: 'notification.created',
|
|
182
|
+
notificationId: notification.id,
|
|
183
|
+
notification,
|
|
184
|
+
});
|
|
185
|
+
return notification;
|
|
86
186
|
}
|
|
87
187
|
|
|
88
188
|
async updateProgress(userId: number, id: number, dto: UpdateProgressDto) {
|
|
89
189
|
await this.assertOwnership(userId, id);
|
|
90
190
|
const finished = dto.progress >= 100;
|
|
91
|
-
|
|
191
|
+
const notification = await this.prisma.notification.update({
|
|
92
192
|
where: { id },
|
|
93
193
|
data: {
|
|
94
194
|
progress: dto.progress,
|
|
@@ -97,6 +197,51 @@ export class NotificationService {
|
|
|
97
197
|
finished_at: finished ? new Date() : undefined,
|
|
98
198
|
},
|
|
99
199
|
});
|
|
200
|
+
await this.broadcastNotificationEvent(userId, {
|
|
201
|
+
type: 'notification.updated',
|
|
202
|
+
notificationId: id,
|
|
203
|
+
notification,
|
|
204
|
+
});
|
|
205
|
+
return notification;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
stream(userId: number, req: Request, res: Response) {
|
|
209
|
+
res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
|
|
210
|
+
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
211
|
+
res.setHeader('Connection', 'keep-alive');
|
|
212
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
213
|
+
res.flushHeaders();
|
|
214
|
+
|
|
215
|
+
const writeEvent = (event: NotificationStreamEvent) => {
|
|
216
|
+
if (res.writableEnded) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
res.write(`event: ${event.type}\n`);
|
|
221
|
+
res.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const eventKey = this.getEventKey(userId);
|
|
225
|
+
const handler = (event: NotificationStreamEvent) => {
|
|
226
|
+
writeEvent(event);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
this.notificationEvents.on(eventKey, handler);
|
|
230
|
+
writeEvent({ type: 'ready' });
|
|
231
|
+
|
|
232
|
+
const heartbeat = setInterval(() => {
|
|
233
|
+
if (!res.writableEnded) {
|
|
234
|
+
res.write(': ping\n\n');
|
|
235
|
+
}
|
|
236
|
+
}, 25000);
|
|
237
|
+
|
|
238
|
+
const cleanup = () => {
|
|
239
|
+
clearInterval(heartbeat);
|
|
240
|
+
this.notificationEvents.off(eventKey, handler);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
req.on('close', cleanup);
|
|
244
|
+
res.on('close', cleanup);
|
|
100
245
|
}
|
|
101
246
|
|
|
102
247
|
async clearOldNotifications(retentionDays: number, batchLimit: number) {
|
|
@@ -121,4 +266,59 @@ export class NotificationService {
|
|
|
121
266
|
if (notification.user_id !== userId) throw new ForbiddenException();
|
|
122
267
|
return notification;
|
|
123
268
|
}
|
|
269
|
+
|
|
270
|
+
private async broadcastNotificationEvent(
|
|
271
|
+
userId: number,
|
|
272
|
+
event: NotificationStreamEvent,
|
|
273
|
+
) {
|
|
274
|
+
this.emitLocalNotificationEvent(userId, event);
|
|
275
|
+
|
|
276
|
+
const payload: ClusterNotificationPayload = {
|
|
277
|
+
...event,
|
|
278
|
+
userId,
|
|
279
|
+
originInstanceId: this.instanceId,
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
await this.prisma.$executeRaw`
|
|
284
|
+
SELECT pg_notify(${this.channelName}, ${JSON.stringify(payload)})
|
|
285
|
+
`;
|
|
286
|
+
} catch (error) {
|
|
287
|
+
this.logger.warn('Failed to broadcast notification event', error as any);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private getEventKey(userId: number) {
|
|
292
|
+
return `notification:${userId}`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
private emitLocalNotificationEvent(
|
|
296
|
+
userId: number,
|
|
297
|
+
event: NotificationStreamEvent,
|
|
298
|
+
) {
|
|
299
|
+
this.notificationEvents.emit(this.getEventKey(userId), event);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private handleClusterNotification(message: PgNotification) {
|
|
303
|
+
if (message.channel !== this.channelName || !message.payload) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
let payload: ClusterNotificationPayload;
|
|
308
|
+
try {
|
|
309
|
+
payload = JSON.parse(message.payload) as ClusterNotificationPayload;
|
|
310
|
+
} catch {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!payload || payload.originInstanceId === this.instanceId) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
this.emitLocalNotificationEvent(payload.userId, {
|
|
319
|
+
type: payload.type,
|
|
320
|
+
notificationId: payload.notificationId,
|
|
321
|
+
notification: payload.notification,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
124
324
|
}
|
package/src/pdf/pdf.service.ts
CHANGED
|
@@ -182,7 +182,7 @@ export class PdfService {
|
|
|
182
182
|
|
|
183
183
|
if (missingRuntime) {
|
|
184
184
|
throw new InternalServerErrorException(
|
|
185
|
-
'Playwright runtime is not available. Run `
|
|
185
|
+
'Playwright runtime is not available. Run `pnpm --filter api run playwright:install` in the API environment.',
|
|
186
186
|
);
|
|
187
187
|
}
|
|
188
188
|
|
|
@@ -81,7 +81,7 @@ export class ProfileController {
|
|
|
81
81
|
|
|
82
82
|
@Post('mfa/email/verify/confirm')
|
|
83
83
|
sendEmailVerificationMfaConfirm(@User() {id}, @Body() data: EmailVerificationDto, @Locale() locale: string) {
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
return this.profileService.confirmEmailVerificationMfa(locale, id, data);
|
|
86
86
|
}
|
|
87
87
|
|
|
@@ -3,12 +3,12 @@ import { getLocaleText, LocaleService } from '@hed-hog/api-locale';
|
|
|
3
3
|
import { PaginationDTO, PaginationService } from '@hed-hog/api-pagination';
|
|
4
4
|
import { PrismaService, setting_type_0f055cd5ea_enum } from '@hed-hog/api-prisma';
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
BadRequestException,
|
|
7
|
+
forwardRef,
|
|
8
|
+
Inject,
|
|
9
|
+
Injectable,
|
|
10
|
+
Logger,
|
|
11
|
+
NotFoundException
|
|
12
12
|
} from '@nestjs/common';
|
|
13
13
|
import * as pako from 'pako';
|
|
14
14
|
import { IntegrationDeveloperApiService } from '../integration/services/integration-developer-api.service';
|
|
@@ -208,6 +208,7 @@ export class SettingService {
|
|
|
208
208
|
'mfa-email-code-length',
|
|
209
209
|
'ai-openai-api-key-enabled',
|
|
210
210
|
'ai-gemini-api-key-enabled',
|
|
211
|
+
'mcp-enabled',
|
|
211
212
|
'date-format',
|
|
212
213
|
'time-format',
|
|
213
214
|
'timezone',
|
|
@@ -974,8 +975,6 @@ export class SettingService {
|
|
|
974
975
|
this.cachedSettings &&
|
|
975
976
|
slugs.every(s => Object.prototype.hasOwnProperty.call(this.cachedSettings, s))
|
|
976
977
|
) {
|
|
977
|
-
this.logger.debug('Returning settings from cache');
|
|
978
|
-
|
|
979
978
|
// Retorna apenas os slugs requisitados do cache
|
|
980
979
|
const cached: Record<string, any> = {};
|
|
981
980
|
slugs.forEach(s => {
|
|
@@ -984,7 +983,7 @@ export class SettingService {
|
|
|
984
983
|
return cached;
|
|
985
984
|
}
|
|
986
985
|
|
|
987
|
-
|
|
986
|
+
|
|
988
987
|
|
|
989
988
|
slug = Array.isArray(slug) ? slug : [slug];
|
|
990
989
|
|
|
@@ -1064,7 +1063,6 @@ export class SettingService {
|
|
|
1064
1063
|
}
|
|
1065
1064
|
|
|
1066
1065
|
setCache(value: Record<string, any>) {
|
|
1067
|
-
this.logger.debug(`Setting settings cache with ${Object.keys(value).length} items`);
|
|
1068
1066
|
Object.keys(value).forEach(key => {
|
|
1069
1067
|
this.cachedSettings[key] = value[key];
|
|
1070
1068
|
});
|
|
@@ -1072,7 +1070,6 @@ export class SettingService {
|
|
|
1072
1070
|
}
|
|
1073
1071
|
|
|
1074
1072
|
clearCache() {
|
|
1075
|
-
this.logger.debug('Clearing settings cache');
|
|
1076
1073
|
this.cachedSettings = {};
|
|
1077
1074
|
}
|
|
1078
1075
|
|
package/src/task/task.service.ts
CHANGED
|
@@ -42,6 +42,9 @@ export class TasksService {
|
|
|
42
42
|
await this.clearOldNotifications();
|
|
43
43
|
this.logger.verbose('++++++++++++++++++++++++++++++++++');
|
|
44
44
|
|
|
45
|
+
await this.clearOldAccessLogs();
|
|
46
|
+
this.logger.verbose('++++++++++++++++++++++++++++++++++');
|
|
47
|
+
|
|
45
48
|
this.logger.verbose('Finished scheduled cleanup tasks');
|
|
46
49
|
this.logger.verbose('++++++++++++++++++++++++++++++++++');
|
|
47
50
|
}
|
|
@@ -270,6 +273,34 @@ export class TasksService {
|
|
|
270
273
|
);
|
|
271
274
|
}
|
|
272
275
|
|
|
276
|
+
private async clearOldAccessLogs(): Promise<void> {
|
|
277
|
+
const settings = await this.settingService.getSettingValues([
|
|
278
|
+
'cleanup-batch-limit',
|
|
279
|
+
'access-log-retention-days',
|
|
280
|
+
]);
|
|
281
|
+
const batchLimit = Number(settings['cleanup-batch-limit']) || 20000;
|
|
282
|
+
const retentionDays = Number(settings['access-log-retention-days']) || 30;
|
|
283
|
+
this.logger.verbose('Starting cleanup of old access logs');
|
|
284
|
+
const startAt = Date.now();
|
|
285
|
+
|
|
286
|
+
await this.prismaService.$executeRaw`
|
|
287
|
+
WITH del AS (
|
|
288
|
+
SELECT id
|
|
289
|
+
FROM access_log
|
|
290
|
+
WHERE created_at < (now() - ${Prisma.sql`INTERVAL '${Prisma.raw(String(retentionDays))} days'`})
|
|
291
|
+
ORDER BY id
|
|
292
|
+
LIMIT ${batchLimit}
|
|
293
|
+
)
|
|
294
|
+
DELETE FROM access_log al
|
|
295
|
+
USING del
|
|
296
|
+
WHERE al.id = del.id
|
|
297
|
+
`;
|
|
298
|
+
|
|
299
|
+
this.logger.verbose(
|
|
300
|
+
`Old access logs cleaned up in ${Date.now() - startAt}ms`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
273
304
|
private async clearOldNotifications(): Promise<void> {
|
|
274
305
|
const settings = await this.settingService.getSettingValues([
|
|
275
306
|
'cleanup-batch-limit',
|
|
@@ -51,8 +51,6 @@ export class TokenService {
|
|
|
51
51
|
return payload;
|
|
52
52
|
} catch (error) {
|
|
53
53
|
|
|
54
|
-
console.log('JWT ERROR', error);
|
|
55
|
-
|
|
56
54
|
// Return 401 for JWT errors (expired, invalid, etc.)
|
|
57
55
|
throw new UnauthorizedException(
|
|
58
56
|
(error as any).message || getLocaleText('accessDenied', locale, 'Access denied.')
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Transform } from 'class-transformer';
|
|
2
|
+
import { PartialType } from '@nestjs/mapped-types';
|
|
3
|
+
import { IsIn, IsInt, IsOptional, IsString } from 'class-validator';
|
|
4
|
+
|
|
5
|
+
const toNullableInteger = ({ value }: { value: unknown }) => {
|
|
6
|
+
if (value === undefined || value === null || value === '') {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return Number(value);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const toOptionalTrimmedString = ({ value }: { value: unknown }) => {
|
|
14
|
+
if (value === undefined || value === null) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return String(value).trim();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export class CreateWebhookActionDTO {
|
|
22
|
+
@IsIn(['email', 'whatsapp_evolution'])
|
|
23
|
+
type: 'email' | 'whatsapp_evolution';
|
|
24
|
+
|
|
25
|
+
@IsOptional()
|
|
26
|
+
@Transform(toOptionalTrimmedString)
|
|
27
|
+
@IsString()
|
|
28
|
+
name?: string;
|
|
29
|
+
|
|
30
|
+
@IsOptional()
|
|
31
|
+
@Transform(toNullableInteger)
|
|
32
|
+
@IsInt()
|
|
33
|
+
order?: number;
|
|
34
|
+
|
|
35
|
+
@IsOptional()
|
|
36
|
+
@IsIn(['active', 'inactive'])
|
|
37
|
+
status?: 'active' | 'inactive';
|
|
38
|
+
|
|
39
|
+
@IsOptional()
|
|
40
|
+
@Transform(toNullableInteger)
|
|
41
|
+
@IsInt()
|
|
42
|
+
mail_profile_id?: number;
|
|
43
|
+
|
|
44
|
+
@IsOptional()
|
|
45
|
+
@Transform(toNullableInteger)
|
|
46
|
+
@IsInt()
|
|
47
|
+
mail_id?: number;
|
|
48
|
+
|
|
49
|
+
@IsOptional()
|
|
50
|
+
@Transform(toOptionalTrimmedString)
|
|
51
|
+
@IsString()
|
|
52
|
+
email_to?: string;
|
|
53
|
+
|
|
54
|
+
@IsOptional()
|
|
55
|
+
@Transform(toOptionalTrimmedString)
|
|
56
|
+
@IsString()
|
|
57
|
+
email_cc?: string;
|
|
58
|
+
|
|
59
|
+
@IsOptional()
|
|
60
|
+
@Transform(toOptionalTrimmedString)
|
|
61
|
+
@IsString()
|
|
62
|
+
email_bcc?: string;
|
|
63
|
+
|
|
64
|
+
@IsOptional()
|
|
65
|
+
@IsIn(['phone', 'group'])
|
|
66
|
+
whatsapp_target_type?: 'phone' | 'group';
|
|
67
|
+
|
|
68
|
+
@IsOptional()
|
|
69
|
+
@Transform(toOptionalTrimmedString)
|
|
70
|
+
@IsString()
|
|
71
|
+
whatsapp_target?: string;
|
|
72
|
+
|
|
73
|
+
@IsOptional()
|
|
74
|
+
@Transform(toOptionalTrimmedString)
|
|
75
|
+
@IsString()
|
|
76
|
+
whatsapp_template?: string;
|
|
77
|
+
|
|
78
|
+
@IsOptional()
|
|
79
|
+
@Transform(toOptionalTrimmedString)
|
|
80
|
+
@IsString()
|
|
81
|
+
whatsapp_instance?: string;
|
|
82
|
+
|
|
83
|
+
@IsOptional()
|
|
84
|
+
@Transform(toOptionalTrimmedString)
|
|
85
|
+
@IsString()
|
|
86
|
+
whatsapp_base_url?: string;
|
|
87
|
+
|
|
88
|
+
@IsOptional()
|
|
89
|
+
@Transform(toOptionalTrimmedString)
|
|
90
|
+
@IsString()
|
|
91
|
+
whatsapp_token?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class UpdateWebhookActionDTO extends PartialType(
|
|
95
|
+
CreateWebhookActionDTO,
|
|
96
|
+
) {}
|