@hed-hog/core 0.0.364 → 0.0.366
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/ai/ai.controller.d.ts +4 -4
- package/dist/ai/ai.module.d.ts.map +1 -1
- package/dist/ai/ai.module.js +2 -0
- package/dist/ai/ai.module.js.map +1 -1
- package/dist/ai/ai.service.d.ts +7 -5
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +63 -31
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/ai-instruction/ai-execution.service.d.ts +45 -0
- package/dist/ai-instruction/ai-execution.service.d.ts.map +1 -0
- package/dist/ai-instruction/ai-execution.service.js +203 -0
- package/dist/ai-instruction/ai-execution.service.js.map +1 -0
- package/dist/ai-instruction/ai-instruction.controller.d.ts +25 -0
- package/dist/ai-instruction/ai-instruction.controller.d.ts.map +1 -0
- package/dist/ai-instruction/ai-instruction.controller.js +117 -0
- package/dist/ai-instruction/ai-instruction.controller.js.map +1 -0
- package/dist/ai-instruction/ai-instruction.module.d.ts +3 -0
- package/dist/ai-instruction/ai-instruction.module.d.ts.map +1 -0
- package/dist/ai-instruction/ai-instruction.module.js +27 -0
- package/dist/ai-instruction/ai-instruction.module.js.map +1 -0
- package/dist/ai-instruction/ai-instruction.service.d.ts +38 -0
- package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -0
- package/dist/ai-instruction/ai-instruction.service.js +289 -0
- package/dist/ai-instruction/ai-instruction.service.js.map +1 -0
- package/dist/ai-instruction/ai-prompt-builder.service.d.ts +53 -0
- package/dist/ai-instruction/ai-prompt-builder.service.d.ts.map +1 -0
- package/dist/ai-instruction/ai-prompt-builder.service.js +132 -0
- package/dist/ai-instruction/ai-prompt-builder.service.js.map +1 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts +12 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts.map +1 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.js +57 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.js.map +1 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts +10 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts.map +1 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.js +56 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.js.map +1 -0
- package/dist/ai-instruction/types/ai-instruction.types.d.ts +78 -0
- package/dist/ai-instruction/types/ai-instruction.types.d.ts.map +1 -0
- package/dist/ai-instruction/types/ai-instruction.types.js +3 -0
- package/dist/ai-instruction/types/ai-instruction.types.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +13 -5
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +39 -20
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.service.d.ts +18 -7
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +20 -16
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +3 -0
- package/dist/core.module.js.map +1 -1
- package/dist/file/file.service.d.ts +37 -0
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +94 -4
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/abstract.provider.d.ts +6 -2
- 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 -1
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +7 -2
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts +4 -1
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +7 -2
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts +2 -2
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +7 -2
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts +4 -1
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +9 -6
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/file/provider/spaces.provider.d.ts +4 -1
- package/dist/file/provider/spaces.provider.d.ts.map +1 -1
- package/dist/file/provider/spaces.provider.js +9 -5
- package/dist/file/provider/spaces.provider.js.map +1 -1
- package/dist/integration-profile/integration-profile.controller.d.ts +3 -3
- package/dist/integration-profile/integration-profile.service.d.ts +3 -3
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.service.js +1 -10
- package/dist/integration-profile/integration-profile.service.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.controller.d.ts +2 -2
- package/dist/mcp-chat/mcp-chat.module.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.module.js +2 -0
- package/dist/mcp-chat/mcp-chat.module.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts +8 -3
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +100 -20
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/notification/notification.service.d.ts +1 -0
- package/dist/notification/notification.service.d.ts.map +1 -1
- package/dist/notification/notification.service.js +29 -1
- package/dist/notification/notification.service.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +1 -0
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +55 -1
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/profile/events/profile-avatar-updated.event.d.ts +7 -0
- package/dist/profile/events/profile-avatar-updated.event.d.ts.map +1 -0
- package/dist/profile/events/profile-avatar-updated.event.js +12 -0
- package/dist/profile/events/profile-avatar-updated.event.js.map +1 -0
- package/dist/profile/events/profile-email-changed.event.d.ts +7 -0
- package/dist/profile/events/profile-email-changed.event.d.ts.map +1 -0
- package/dist/profile/events/profile-email-changed.event.js +12 -0
- package/dist/profile/events/profile-email-changed.event.js.map +1 -0
- package/dist/profile/events/profile-updated.event.d.ts +7 -0
- package/dist/profile/events/profile-updated.event.d.ts.map +1 -0
- package/dist/profile/events/profile-updated.event.js +12 -0
- package/dist/profile/events/profile-updated.event.js.map +1 -0
- package/dist/profile/profile.service.d.ts +3 -1
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +28 -17
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/session/session.controller.d.ts +1 -0
- package/dist/session/session.controller.d.ts.map +1 -1
- package/dist/session/session.service.d.ts +9 -4
- package/dist/session/session.service.d.ts.map +1 -1
- package/dist/session/session.service.js +61 -51
- package/dist/session/session.service.js.map +1 -1
- package/dist/setting/setting.controller.d.ts +5 -5
- package/dist/setting/setting.service.d.ts +5 -5
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +2 -0
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/task/task.service.d.ts +8 -11
- package/dist/task/task.service.d.ts.map +1 -1
- package/dist/task/task.service.js +10 -16
- package/dist/task/task.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +1 -0
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.service.d.ts +3 -0
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-command.registry.d.ts +9 -2
- package/dist/webhook-integration/webhook-command.registry.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-command.registry.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +15 -7
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/hedhog/data/integration_provider.yaml +17 -0
- package/hedhog/data/integration_type.yaml +6 -0
- package/hedhog/data/route.yaml +86 -2
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +109 -0
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +6 -6
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +169 -14
- package/hedhog/frontend/messages/en.json +11 -2
- package/hedhog/frontend/messages/pt.json +11 -2
- package/hedhog/table/ai_execution.yaml +79 -0
- package/hedhog/table/ai_execution_step.yaml +65 -0
- package/hedhog/table/ai_instruction.yaml +43 -0
- package/hedhog/table/ai_instruction_version.yaml +30 -0
- package/hedhog/table/ai_model_pricing.yaml +35 -0
- package/hedhog/table/user_session.yaml +2 -0
- package/package.json +3 -2
- package/src/ai/ai.module.ts +2 -0
- package/src/ai/ai.service.ts +64 -31
- package/src/ai-instruction/ai-execution.service.ts +244 -0
- package/src/ai-instruction/ai-instruction.controller.ts +73 -0
- package/src/ai-instruction/ai-instruction.module.ts +14 -0
- package/src/ai-instruction/ai-instruction.service.ts +343 -0
- package/src/ai-instruction/ai-prompt-builder.service.ts +142 -0
- package/src/ai-instruction/dto/create-ai-instruction.dto.ts +36 -0
- package/src/ai-instruction/dto/update-ai-instruction.dto.ts +35 -0
- package/src/ai-instruction/types/ai-instruction.types.ts +90 -0
- package/src/auth/auth.controller.ts +23 -5
- package/src/auth/auth.service.ts +26 -15
- package/src/core.module.ts +3 -0
- package/src/file/file.service.ts +136 -4
- package/src/file/provider/abstract.provider.ts +4 -2
- package/src/file/provider/azure.provider.ts +6 -3
- package/src/file/provider/gcs.provider.ts +5 -3
- package/src/file/provider/local.provider.ts +7 -3
- package/src/file/provider/s3.provider.ts +8 -6
- package/src/file/provider/spaces.provider.ts +8 -7
- package/src/integration-profile/integration-profile.service.ts +1 -10
- package/src/mcp-chat/mcp-chat.module.ts +19 -17
- package/src/mcp-chat/mcp-chat.service.ts +95 -9
- package/src/notification/notification.service.ts +32 -1
- package/src/oauth/oauth.service.ts +74 -1
- package/src/profile/events/profile-avatar-updated.event.ts +8 -0
- package/src/profile/events/profile-email-changed.event.ts +8 -0
- package/src/profile/events/profile-updated.event.ts +8 -0
- package/src/profile/profile.service.ts +25 -16
- package/src/session/session.service.ts +70 -52
- package/src/setting/setting.service.ts +10 -8
- package/src/task/task.service.ts +10 -16
- package/src/webhook-integration/webhook-command.registry.ts +10 -2
- package/src/webhook-integration/webhook-integration.service.ts +33 -6
|
@@ -46,6 +46,17 @@ export class AuthController {
|
|
|
46
46
|
return this.service.verifyUser(locale, id);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
@NoRole()
|
|
50
|
+
@Get('desktop-token')
|
|
51
|
+
async desktopToken(
|
|
52
|
+
@User() { id },
|
|
53
|
+
@Locale() locale: string,
|
|
54
|
+
@Ip() ipAddress: string,
|
|
55
|
+
@Headers('user-agent') userAgent: string,
|
|
56
|
+
) {
|
|
57
|
+
return this.service.issueDesktopToken(locale, id, ipAddress, userAgent);
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
@NoRole()
|
|
50
61
|
@Get('roles')
|
|
51
62
|
async roles(@UserOptional() user, @Locale() locale: string) {
|
|
@@ -61,12 +72,13 @@ export class AuthController {
|
|
|
61
72
|
@Res({ passthrough: true }) res,
|
|
62
73
|
@Body('refreshToken') refreshTokenFromBody: string,
|
|
63
74
|
@Headers('user-agent') userAgent: string,
|
|
75
|
+
@Headers('x-browser-id') browserId: string,
|
|
64
76
|
@Ip() ipAddress: string
|
|
65
77
|
) {
|
|
66
78
|
const tokenSource = req.cookies['rt'] ? 'cookie' : (refreshTokenFromBody ? 'body' : 'none');
|
|
67
79
|
this.logger.debug(`[AuthController] POST /auth/refresh tokenSource=${tokenSource} ip=${ipAddress}`);
|
|
68
80
|
const currentRefreshToken = req.cookies['rt'] || refreshTokenFromBody;
|
|
69
|
-
const { session, refreshToken, accessToken } = await this.service.refreshAccessToken(locale, currentRefreshToken, ipAddress, userAgent);
|
|
81
|
+
const { session, refreshToken, accessToken } = await this.service.refreshAccessToken(locale, currentRefreshToken, ipAddress, userAgent, browserId || null);
|
|
70
82
|
await this.token.setRefreshTokenCookie(locale, res, refreshToken, session.expires_at);
|
|
71
83
|
|
|
72
84
|
return {
|
|
@@ -82,9 +94,10 @@ export class AuthController {
|
|
|
82
94
|
@Body() data: LoginDTO,
|
|
83
95
|
@Ip() ipAddress: string,
|
|
84
96
|
@Headers('user-agent') userAgent: string,
|
|
97
|
+
@Headers('x-browser-id') browserId: string,
|
|
85
98
|
@Res({ passthrough: true }) res,
|
|
86
99
|
) {
|
|
87
|
-
return this.service.loginWithEmailAndPassword(res, locale, ipAddress, userAgent, data);
|
|
100
|
+
return this.service.loginWithEmailAndPassword(res, locale, ipAddress, userAgent, data, browserId || null);
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
@Public()
|
|
@@ -94,9 +107,10 @@ export class AuthController {
|
|
|
94
107
|
@Body() {token, code}: LoginEmailVerificationDTO,
|
|
95
108
|
@Ip() ipAddress: string,
|
|
96
109
|
@Headers('user-agent') userAgent: string,
|
|
110
|
+
@Headers('x-browser-id') browserId: string,
|
|
97
111
|
@Res({ passthrough: true }) res,
|
|
98
112
|
) {
|
|
99
|
-
return this.service.emailVerificationLogin(locale, token, code, ipAddress, userAgent, res);
|
|
113
|
+
return this.service.emailVerificationLogin(locale, token, code, ipAddress, userAgent, res, browserId || null);
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
@Public()
|
|
@@ -124,6 +138,7 @@ export class AuthController {
|
|
|
124
138
|
@Body() { token, code, methodType }: LoginWithCodeDTO,
|
|
125
139
|
@Ip() ipAddress: string,
|
|
126
140
|
@Headers('user-agent') userAgent: string,
|
|
141
|
+
@Headers('x-browser-id') browserId: string,
|
|
127
142
|
@Res({ passthrough: true }) res,
|
|
128
143
|
) {
|
|
129
144
|
const { accessToken, refreshToken, session, requiresPasswordReset } = await this.service.verifyMfaCode(
|
|
@@ -132,7 +147,8 @@ export class AuthController {
|
|
|
132
147
|
code,
|
|
133
148
|
ipAddress,
|
|
134
149
|
userAgent,
|
|
135
|
-
methodType
|
|
150
|
+
methodType,
|
|
151
|
+
browserId || null,
|
|
136
152
|
);
|
|
137
153
|
|
|
138
154
|
await this.token.setRefreshTokenCookie(locale, res, refreshToken, session.expires_at);
|
|
@@ -146,6 +162,7 @@ export class AuthController {
|
|
|
146
162
|
@Body() { token, code }: LoginWithRecoveryCodeDTO,
|
|
147
163
|
@Ip() ipAddress: string,
|
|
148
164
|
@Headers('user-agent') userAgent: string,
|
|
165
|
+
@Headers('x-browser-id') browserId: string,
|
|
149
166
|
@Res({ passthrough: true }) res,
|
|
150
167
|
) {
|
|
151
168
|
const { accessToken, refreshToken, session, requiresPasswordReset } = await this.service.verifyMfaRecoveryCode(
|
|
@@ -153,7 +170,8 @@ export class AuthController {
|
|
|
153
170
|
token,
|
|
154
171
|
code,
|
|
155
172
|
ipAddress,
|
|
156
|
-
userAgent
|
|
173
|
+
userAgent,
|
|
174
|
+
browserId || null,
|
|
157
175
|
);
|
|
158
176
|
|
|
159
177
|
await this.token.setRefreshTokenCookie(locale, res, refreshToken, session.expires_at);
|
package/src/auth/auth.service.ts
CHANGED
|
@@ -43,8 +43,8 @@ export class AuthService {
|
|
|
43
43
|
private readonly challenge: ChallengeService,
|
|
44
44
|
) { }
|
|
45
45
|
|
|
46
|
-
async getAuthenticationPayload(locale: string, userId: number, ipAddress: string, userAgent: string) {
|
|
47
|
-
const { token: refreshToken, session } = await this.session.create(locale, userId, ipAddress, userAgent);
|
|
46
|
+
async getAuthenticationPayload(locale: string, userId: number, ipAddress: string, userAgent: string, browserId?: string | null) {
|
|
47
|
+
const { token: refreshToken, session } = await this.session.create(locale, userId, ipAddress, userAgent, browserId);
|
|
48
48
|
const payload = { sub: userId, sessionId: session.id };
|
|
49
49
|
const accessToken = await this.token.createAccessToken(payload);
|
|
50
50
|
await this.prisma.user.update({ where: { id: userId }, data: { last_login_at: new Date() } });
|
|
@@ -58,6 +58,11 @@ export class AuthService {
|
|
|
58
58
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
async issueDesktopToken(locale: string, userId: number, ipAddress: string, userAgent: string) {
|
|
62
|
+
const { accessToken, refreshToken } = await this.getAuthenticationPayload(locale, userId, ipAddress, userAgent);
|
|
63
|
+
return { accessToken, refreshToken };
|
|
64
|
+
}
|
|
65
|
+
|
|
61
66
|
private hasPendingPasswordReset(user: User | any) {
|
|
62
67
|
return Boolean(
|
|
63
68
|
user?.user_credential?.some(
|
|
@@ -264,7 +269,7 @@ export class AuthService {
|
|
|
264
269
|
}
|
|
265
270
|
}
|
|
266
271
|
|
|
267
|
-
async emailVerificationLogin(locale: string, token: string, code: string, ipAddress: string, userAgent: string, res: any) {
|
|
272
|
+
async emailVerificationLogin(locale: string, token: string, code: string, ipAddress: string, userAgent: string, res: any, browserId?: string | null) {
|
|
268
273
|
|
|
269
274
|
try {
|
|
270
275
|
const payload = await this.token.verify(locale, token);
|
|
@@ -317,14 +322,14 @@ export class AuthService {
|
|
|
317
322
|
|
|
318
323
|
const user = await this.user.findUserById(locale, challenge.user_identifier.user_id);
|
|
319
324
|
|
|
320
|
-
return this.login(locale, user as unknown as User, ipAddress, userAgent, res);
|
|
325
|
+
return this.login(locale, user as unknown as User, ipAddress, userAgent, res, browserId);
|
|
321
326
|
|
|
322
327
|
} catch (error) {
|
|
323
328
|
throw error;
|
|
324
329
|
}
|
|
325
330
|
}
|
|
326
331
|
|
|
327
|
-
private async login(locale: string, user: User, ipAddress: string, userAgent: string, res: any) {
|
|
332
|
+
private async login(locale: string, user: User, ipAddress: string, userAgent: string, res: any, browserId?: string | null) {
|
|
328
333
|
|
|
329
334
|
const emails = await this.prisma.user_identifier.findMany({
|
|
330
335
|
where: {
|
|
@@ -342,7 +347,8 @@ export class AuthService {
|
|
|
342
347
|
locale,
|
|
343
348
|
user.id,
|
|
344
349
|
ipAddress,
|
|
345
|
-
userAgent
|
|
350
|
+
userAgent,
|
|
351
|
+
browserId,
|
|
346
352
|
);
|
|
347
353
|
|
|
348
354
|
for (const emailObj of emails) {
|
|
@@ -382,6 +388,7 @@ export class AuthService {
|
|
|
382
388
|
ipAddress: string,
|
|
383
389
|
userAgent: string,
|
|
384
390
|
{ email, password }: LoginDTO,
|
|
391
|
+
browserId?: string | null,
|
|
385
392
|
) {
|
|
386
393
|
|
|
387
394
|
const user = await this.user.findUserByEmail(locale, email);
|
|
@@ -446,7 +453,7 @@ export class AuthService {
|
|
|
446
453
|
|
|
447
454
|
}
|
|
448
455
|
|
|
449
|
-
return this.login(locale, user as unknown as User, ipAddress, userAgent, res);
|
|
456
|
+
return this.login(locale, user as unknown as User, ipAddress, userAgent, res, browserId);
|
|
450
457
|
}
|
|
451
458
|
|
|
452
459
|
async verifyRoles(_locale: string, userId: number) {
|
|
@@ -474,7 +481,7 @@ export class AuthService {
|
|
|
474
481
|
};
|
|
475
482
|
}
|
|
476
483
|
|
|
477
|
-
async refreshAccessToken(locale: string, refreshToken: string, ipAddress: string, userAgent: string) {
|
|
484
|
+
async refreshAccessToken(locale: string, refreshToken: string, ipAddress: string, userAgent: string, browserId?: string | null) {
|
|
478
485
|
|
|
479
486
|
if (!refreshToken) {
|
|
480
487
|
this.logger.warn(`[AuthService] refreshAccessToken called without token ip=${ipAddress}`);
|
|
@@ -487,7 +494,8 @@ export class AuthService {
|
|
|
487
494
|
locale,
|
|
488
495
|
refreshToken,
|
|
489
496
|
ipAddress,
|
|
490
|
-
userAgent
|
|
497
|
+
userAgent,
|
|
498
|
+
browserId,
|
|
491
499
|
);
|
|
492
500
|
|
|
493
501
|
const user = await this.user.findUserById(locale, session.user_id);
|
|
@@ -573,7 +581,7 @@ export class AuthService {
|
|
|
573
581
|
return { accessToken, refreshToken, session }
|
|
574
582
|
}
|
|
575
583
|
|
|
576
|
-
async verifyMfaCode(locale: string, mfaToken: string, code: string, ipAddress: string, userAgent: string, methodType?: 'totp' | 'email' | 'recovery') {
|
|
584
|
+
async verifyMfaCode(locale: string, mfaToken: string, code: string, ipAddress: string, userAgent: string, methodType?: 'totp' | 'email' | 'recovery', browserId?: string | null) {
|
|
577
585
|
const payload = await this.token.verifyMfaChallengeToken(mfaToken);
|
|
578
586
|
const user = await this.prisma.user.findUnique({
|
|
579
587
|
where: { id: payload.userId },
|
|
@@ -673,7 +681,8 @@ export class AuthService {
|
|
|
673
681
|
locale,
|
|
674
682
|
user.id,
|
|
675
683
|
ipAddress,
|
|
676
|
-
userAgent
|
|
684
|
+
userAgent,
|
|
685
|
+
browserId,
|
|
677
686
|
);
|
|
678
687
|
|
|
679
688
|
this.mail.sendTemplatedMail(
|
|
@@ -697,7 +706,7 @@ export class AuthService {
|
|
|
697
706
|
return { accessToken, refreshToken, session, requiresPasswordReset };
|
|
698
707
|
}
|
|
699
708
|
|
|
700
|
-
async verifyMfaRecoveryCode(locale: string, mfaToken: string, recoveryCode: string, ipAddress: string, userAgent: string) {
|
|
709
|
+
async verifyMfaRecoveryCode(locale: string, mfaToken: string, recoveryCode: string, ipAddress: string, userAgent: string, browserId?: string | null) {
|
|
701
710
|
const payload = await this.token.verifyMfaChallengeToken(mfaToken);
|
|
702
711
|
const user = await this.prisma.user.findUnique({
|
|
703
712
|
where: { id: payload.userId },
|
|
@@ -729,7 +738,8 @@ export class AuthService {
|
|
|
729
738
|
locale,
|
|
730
739
|
user.id,
|
|
731
740
|
ipAddress,
|
|
732
|
-
userAgent
|
|
741
|
+
userAgent,
|
|
742
|
+
browserId,
|
|
733
743
|
);
|
|
734
744
|
|
|
735
745
|
await this.user.registerUserActivity(user.id, "login");
|
|
@@ -815,7 +825,7 @@ export class AuthService {
|
|
|
815
825
|
return options;
|
|
816
826
|
}
|
|
817
827
|
|
|
818
|
-
async verifyWebAuthnAuthentication(locale: string, mfaToken: string, assertionResponse: any, ipAddress: string, userAgent: string) {
|
|
828
|
+
async verifyWebAuthnAuthentication(locale: string, mfaToken: string, assertionResponse: any, ipAddress: string, userAgent: string, browserId?: string | null) {
|
|
819
829
|
const { verifyAuthenticationResponse } = await import('@simplewebauthn/server');
|
|
820
830
|
const payload = await this.token.verifyMfaChallengeToken(mfaToken);
|
|
821
831
|
const userId = payload.userId;
|
|
@@ -880,7 +890,8 @@ export class AuthService {
|
|
|
880
890
|
locale,
|
|
881
891
|
userId,
|
|
882
892
|
ipAddress,
|
|
883
|
-
userAgent
|
|
893
|
+
userAgent,
|
|
894
|
+
browserId,
|
|
884
895
|
);
|
|
885
896
|
|
|
886
897
|
const user = await this.prisma.user.findFirst({ where: { id: userId } });
|
package/src/core.module.ts
CHANGED
|
@@ -41,6 +41,7 @@ import { IsEmailWithSettingsConstraint } from './validators/is-email-with-settin
|
|
|
41
41
|
import { IsPinCodeWithSettingConstraint } from './validators/is-pin-code-with-setting.validator';
|
|
42
42
|
import { IsStrongPasswordWithSettingsConstraint } from './validators/is-strong-password-with-settings.validator';
|
|
43
43
|
import { ValidatorServiceLocator } from './validators/service-locator';
|
|
44
|
+
import { AiInstructionModule } from './ai-instruction/ai-instruction.module';
|
|
44
45
|
import { IntegrationProfileModule } from './integration-profile/integration-profile.module';
|
|
45
46
|
import { WebhookIntegrationModule } from './webhook-integration/webhook-integration.module';
|
|
46
47
|
|
|
@@ -76,6 +77,7 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
|
|
|
76
77
|
forwardRef(() => OAuthModule),
|
|
77
78
|
forwardRef(() => IntegrationModule),
|
|
78
79
|
forwardRef(() => WebhookIntegrationModule),
|
|
80
|
+
forwardRef(() => AiInstructionModule),
|
|
79
81
|
forwardRef(() => McpModule),
|
|
80
82
|
forwardRef(() => McpChatModule),
|
|
81
83
|
forwardRef(() => PdfModule),
|
|
@@ -97,6 +99,7 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
|
|
|
97
99
|
FileModule,
|
|
98
100
|
SessionModule,
|
|
99
101
|
AiModule,
|
|
102
|
+
AiInstructionModule,
|
|
100
103
|
IntegrationModule,
|
|
101
104
|
WebhookIntegrationModule,
|
|
102
105
|
IsStrongPasswordWithSettingsConstraint,
|
package/src/file/file.service.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
CreateFunctionCommand,
|
|
11
11
|
GetFunctionConfigurationCommand,
|
|
12
12
|
LambdaClient,
|
|
13
|
+
UpdateFunctionCodeCommand,
|
|
13
14
|
UpdateFunctionConfigurationCommand,
|
|
14
15
|
} from '@aws-sdk/client-lambda';
|
|
15
16
|
import {
|
|
@@ -291,6 +292,43 @@ export class FileService implements OnModuleInit {
|
|
|
291
292
|
}
|
|
292
293
|
}
|
|
293
294
|
|
|
295
|
+
async openReadStreamWithRange(fileId: number, start?: number, end?: number) {
|
|
296
|
+
if (!fileId) throw new BadRequestException('No file ID provided');
|
|
297
|
+
|
|
298
|
+
const file = await this.prismaService.file.findUnique({
|
|
299
|
+
where: { id: fileId },
|
|
300
|
+
include: { file_mimetype: true },
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if (!file) throw new NotFoundException(`File not found: ${fileId}`);
|
|
304
|
+
|
|
305
|
+
const provider = await this.getProvider();
|
|
306
|
+
const providerPath = this.resolveProviderPath(file);
|
|
307
|
+
const totalSize: number = file.size ?? 0;
|
|
308
|
+
|
|
309
|
+
const resolvedStart = start ?? 0;
|
|
310
|
+
const resolvedEnd = end !== undefined ? end : totalSize > 0 ? totalSize - 1 : undefined;
|
|
311
|
+
const hasRange = start !== undefined;
|
|
312
|
+
|
|
313
|
+
const stream = await provider.readStream(
|
|
314
|
+
providerPath,
|
|
315
|
+
hasRange ? { start: resolvedStart, end: resolvedEnd } : undefined,
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
const contentLength =
|
|
319
|
+
resolvedEnd !== undefined ? resolvedEnd - resolvedStart + 1 : totalSize;
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
file,
|
|
323
|
+
stream,
|
|
324
|
+
totalSize,
|
|
325
|
+
start: resolvedStart,
|
|
326
|
+
end: resolvedEnd,
|
|
327
|
+
contentLength,
|
|
328
|
+
mimetype: file.file_mimetype?.name ?? 'application/octet-stream',
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
294
332
|
async downloadToPath(
|
|
295
333
|
fileId: number,
|
|
296
334
|
destinationPath: string,
|
|
@@ -834,10 +872,40 @@ export class FileService implements OnModuleInit {
|
|
|
834
872
|
}),
|
|
835
873
|
);
|
|
836
874
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
875
|
+
this.logger.log(
|
|
876
|
+
`updateLambdaEnvironmentVariables: fn=${params.functionName} region=${params.region} ` +
|
|
877
|
+
`currentStatus=${current.LastUpdateStatus} ` +
|
|
878
|
+
`incomingKeys=[${Object.keys(params.environmentVariables).join(',')}]`,
|
|
879
|
+
);
|
|
880
|
+
|
|
881
|
+
const LAMBDA_RESERVED_KEYS = new Set([
|
|
882
|
+
'AWS_REGION',
|
|
883
|
+
'AWS_DEFAULT_REGION',
|
|
884
|
+
'AWS_LAMBDA_FUNCTION_NAME',
|
|
885
|
+
'AWS_LAMBDA_FUNCTION_MEMORY_SIZE',
|
|
886
|
+
'AWS_LAMBDA_FUNCTION_VERSION',
|
|
887
|
+
'AWS_LAMBDA_LOG_GROUP_NAME',
|
|
888
|
+
'AWS_LAMBDA_LOG_STREAM_NAME',
|
|
889
|
+
'AWS_LAMBDA_RUNTIME_API',
|
|
890
|
+
'AWS_EXECUTION_ENV',
|
|
891
|
+
'LAMBDA_TASK_ROOT',
|
|
892
|
+
'LAMBDA_RUNTIME_DIR',
|
|
893
|
+
'TZ',
|
|
894
|
+
'_HANDLER',
|
|
895
|
+
]);
|
|
896
|
+
|
|
897
|
+
const merged = Object.fromEntries(
|
|
898
|
+
Object.entries({
|
|
899
|
+
...(current.Environment?.Variables ?? {}),
|
|
900
|
+
...params.environmentVariables,
|
|
901
|
+
}).filter(([key]) => !LAMBDA_RESERVED_KEYS.has(key)),
|
|
902
|
+
);
|
|
903
|
+
|
|
904
|
+
this.logger.log(
|
|
905
|
+
`updateLambdaEnvironmentVariables: sending merged keys=[${Object.keys(merged).join(',')}] ` +
|
|
906
|
+
`WEBHOOK_URL=${merged['WEBHOOK_URL'] ?? '(not set)'} ` +
|
|
907
|
+
`WEBHOOK_SECRET_LEN=${merged['WEBHOOK_SECRET']?.length ?? 0}`,
|
|
908
|
+
);
|
|
841
909
|
|
|
842
910
|
await lambda.send(
|
|
843
911
|
new UpdateFunctionConfigurationCommand({
|
|
@@ -848,12 +916,76 @@ export class FileService implements OnModuleInit {
|
|
|
848
916
|
}),
|
|
849
917
|
);
|
|
850
918
|
|
|
919
|
+
this.logger.log(`updateLambdaEnvironmentVariables: UpdateFunctionConfiguration sent, polling for completion`);
|
|
920
|
+
|
|
921
|
+
// Wait for configuration update to leave InProgress before returning.
|
|
922
|
+
const cfgDeadline = Date.now() + 60_000;
|
|
923
|
+
let finalStatus = 'unknown';
|
|
924
|
+
let confirmedVars: Record<string, string> = {};
|
|
925
|
+
while (Date.now() < cfgDeadline) {
|
|
926
|
+
const poll = await lambda.send(
|
|
927
|
+
new GetFunctionConfigurationCommand({ FunctionName: params.functionName }),
|
|
928
|
+
);
|
|
929
|
+
finalStatus = poll.LastUpdateStatus ?? 'unknown';
|
|
930
|
+
confirmedVars = (poll.Environment?.Variables ?? {}) as Record<string, string>;
|
|
931
|
+
if (finalStatus !== 'InProgress') break;
|
|
932
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
this.logger.log(
|
|
936
|
+
`updateLambdaEnvironmentVariables: done, finalStatus=${finalStatus} ` +
|
|
937
|
+
`confirmedKeys=[${Object.keys(confirmedVars).join(',')}] ` +
|
|
938
|
+
`confirmedWEBHOOK_URL=${confirmedVars['WEBHOOK_URL'] ?? '(missing)'} ` +
|
|
939
|
+
`confirmedWEBHOOK_SECRET_LEN=${confirmedVars['WEBHOOK_SECRET']?.length ?? 0}`,
|
|
940
|
+
);
|
|
941
|
+
|
|
851
942
|
return {
|
|
852
943
|
functionName: current.FunctionName ?? params.functionName,
|
|
853
944
|
functionArn: current.FunctionArn ?? null,
|
|
854
945
|
};
|
|
855
946
|
}
|
|
856
947
|
|
|
948
|
+
async updateLambdaFunctionCode(params: {
|
|
949
|
+
functionName: string;
|
|
950
|
+
region: string;
|
|
951
|
+
accessKeyId: string;
|
|
952
|
+
secretAccessKey: string;
|
|
953
|
+
sessionToken?: string;
|
|
954
|
+
zipFile: Uint8Array;
|
|
955
|
+
}) {
|
|
956
|
+
const lambda = new LambdaClient({
|
|
957
|
+
region: params.region,
|
|
958
|
+
credentials: {
|
|
959
|
+
accessKeyId: params.accessKeyId,
|
|
960
|
+
secretAccessKey: params.secretAccessKey,
|
|
961
|
+
...(params.sessionToken ? { sessionToken: params.sessionToken } : {}),
|
|
962
|
+
},
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
const result = await lambda.send(
|
|
966
|
+
new UpdateFunctionCodeCommand({
|
|
967
|
+
FunctionName: params.functionName,
|
|
968
|
+
ZipFile: params.zipFile,
|
|
969
|
+
}),
|
|
970
|
+
);
|
|
971
|
+
|
|
972
|
+
// Wait until the function leaves InProgress state before returning,
|
|
973
|
+
// so subsequent UpdateFunctionConfiguration calls don't get ResourceConflictException.
|
|
974
|
+
const deadline = Date.now() + 60_000;
|
|
975
|
+
while (Date.now() < deadline) {
|
|
976
|
+
const config = await lambda.send(
|
|
977
|
+
new GetFunctionConfigurationCommand({ FunctionName: params.functionName }),
|
|
978
|
+
);
|
|
979
|
+
if (config.LastUpdateStatus !== 'InProgress') break;
|
|
980
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
return {
|
|
984
|
+
functionName: result.FunctionName ?? params.functionName,
|
|
985
|
+
functionArn: result.FunctionArn ?? null,
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
857
989
|
async createLambdaFunctionIfMissing(params: {
|
|
858
990
|
functionName: string;
|
|
859
991
|
region: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { v4 } from 'uuid';
|
|
2
2
|
import { MulterFile } from '../../types/multer';
|
|
3
3
|
|
|
4
|
+
export type ReadStreamOptions = { start?: number; end?: number };
|
|
5
|
+
|
|
4
6
|
interface IProvider {
|
|
5
7
|
uploadFromString(
|
|
6
8
|
destination: string,
|
|
@@ -14,7 +16,7 @@ interface IProvider {
|
|
|
14
16
|
filePath: string,
|
|
15
17
|
options?: { filename?: string; mimetype?: string },
|
|
16
18
|
): Promise<any>;
|
|
17
|
-
readStream(filepath: string): Promise<any>;
|
|
19
|
+
readStream(filepath: string, options?: ReadStreamOptions): Promise<any>;
|
|
18
20
|
delete(filepath: string): Promise<any>;
|
|
19
21
|
metaData(filepath: string): Promise<any>;
|
|
20
22
|
buffer(filepath: string): Promise<any>;
|
|
@@ -35,7 +37,7 @@ export abstract class AbstractProvider implements IProvider {
|
|
|
35
37
|
filePath: string,
|
|
36
38
|
options?: { filename?: string; mimetype?: string },
|
|
37
39
|
): Promise<any>;
|
|
38
|
-
abstract readStream(filepath: string): Promise<any>;
|
|
40
|
+
abstract readStream(filepath: string, options?: ReadStreamOptions): Promise<any>;
|
|
39
41
|
abstract delete(filepath: string): Promise<any>;
|
|
40
42
|
abstract metaData(filepath: string): Promise<any>;
|
|
41
43
|
abstract buffer(filepath: string): Promise<any>;
|
|
@@ -120,14 +120,17 @@ export class AzureProvider extends AbstractProvider {
|
|
|
120
120
|
return await blobClient.delete();
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
async readStream(filepath: string): Promise<any> {
|
|
123
|
+
async readStream(filepath: string, options?: { start?: number; end?: number }): Promise<any> {
|
|
124
124
|
const blobServiceClient = await this.getClient();
|
|
125
125
|
const containerClient = blobServiceClient.getContainerClient(
|
|
126
126
|
this.setting['storage-abs-container'],
|
|
127
127
|
);
|
|
128
128
|
const blobClient = containerClient.getBlockBlobClient(filepath);
|
|
129
|
-
|
|
130
|
-
const
|
|
129
|
+
const offset = options?.start ?? 0;
|
|
130
|
+
const count = options?.start !== undefined && options?.end !== undefined
|
|
131
|
+
? options.end - options.start + 1
|
|
132
|
+
: undefined;
|
|
133
|
+
const downloadBlockBlobResponse = await blobClient.download(offset, count);
|
|
131
134
|
return downloadBlockBlobResponse.readableStreamBody;
|
|
132
135
|
}
|
|
133
136
|
|
|
@@ -87,12 +87,14 @@ export class GCSProvider extends AbstractProvider {
|
|
|
87
87
|
|
|
88
88
|
return objectPath;
|
|
89
89
|
}
|
|
90
|
-
async readStream(filepath: string): Promise<any> {
|
|
90
|
+
async readStream(filepath: string, options?: { start?: number; end?: number }): Promise<any> {
|
|
91
91
|
const storage = await this.getClient();
|
|
92
92
|
const bucket = storage.bucket(this.setting['storage-gcs-bucket']);
|
|
93
93
|
const file = bucket.file(filepath);
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const rangeOpts: any = {};
|
|
95
|
+
if (options?.start !== undefined) rangeOpts.start = options.start;
|
|
96
|
+
if (options?.end !== undefined) rangeOpts.end = options.end;
|
|
97
|
+
return file.createReadStream(Object.keys(rangeOpts).length > 0 ? rangeOpts : undefined);
|
|
96
98
|
}
|
|
97
99
|
async delete(filepath: string): Promise<any> {
|
|
98
100
|
const storage = await this.getClient();
|
|
@@ -5,7 +5,7 @@ import { copyFile, mkdir, stat, unlink, writeFile } from 'fs/promises';
|
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { basename, join, sep } from 'path';
|
|
7
7
|
import { Stream } from 'stream';
|
|
8
|
-
import { AbstractProvider } from './abstract.provider';
|
|
8
|
+
import { AbstractProvider, ReadStreamOptions } from './abstract.provider';
|
|
9
9
|
|
|
10
10
|
export class LocalProvider extends AbstractProvider {
|
|
11
11
|
constructor(
|
|
@@ -127,14 +127,18 @@ export class LocalProvider extends AbstractProvider {
|
|
|
127
127
|
return unlink(fullPath);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
async readStream(filepath: string): Promise<Stream> {
|
|
130
|
+
async readStream(filepath: string, options?: ReadStreamOptions): Promise<Stream> {
|
|
131
131
|
const fullPath = this.resolveFilepath(filepath);
|
|
132
132
|
|
|
133
133
|
if (!existsSync(fullPath)) {
|
|
134
134
|
throw new BadRequestException(`File not found: ${fullPath}`);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
const rangeOpts: { start?: number; end?: number } = {};
|
|
138
|
+
if (options?.start !== undefined) rangeOpts.start = options.start;
|
|
139
|
+
if (options?.end !== undefined) rangeOpts.end = options.end;
|
|
140
|
+
|
|
141
|
+
return createReadStream(fullPath, Object.keys(rangeOpts).length > 0 ? rangeOpts : undefined);
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
async metaData(filepath: string): Promise<any> {
|
|
@@ -184,14 +184,16 @@ export class S3Provider extends AbstractProvider {
|
|
|
184
184
|
return true;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
async readStream(filepath: string): Promise<Readable> {
|
|
187
|
+
async readStream(filepath: string, options?: { start?: number; end?: number }): Promise<Readable> {
|
|
188
188
|
const s3 = await this.getClient();
|
|
189
189
|
const key = this.resolveS3Key(filepath);
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
190
|
+
const params: any = { Bucket: this.setting['storage-s3-bucket'], Key: key };
|
|
191
|
+
if (options?.start !== undefined || options?.end !== undefined) {
|
|
192
|
+
const start = options?.start ?? 0;
|
|
193
|
+
const end = options?.end !== undefined ? options.end : '';
|
|
194
|
+
params.Range = `bytes=${start}-${end}`;
|
|
195
|
+
}
|
|
196
|
+
const result = await s3.send(new GetObjectCommand(params));
|
|
195
197
|
// @ts-ignore
|
|
196
198
|
return result.Body as Readable;
|
|
197
199
|
}
|
|
@@ -209,15 +209,16 @@ export class SpacesProvider extends AbstractProvider {
|
|
|
209
209
|
return true;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
async readStream(filepath: string): Promise<Readable> {
|
|
212
|
+
async readStream(filepath: string, options?: { start?: number; end?: number }): Promise<Readable> {
|
|
213
213
|
const s3 = await this.getClient();
|
|
214
214
|
const key = this.resolveKey(filepath);
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
215
|
+
const params: any = { Bucket: this.setting['storage-spaces-bucket'], Key: key };
|
|
216
|
+
if (options?.start !== undefined || options?.end !== undefined) {
|
|
217
|
+
const start = options?.start ?? 0;
|
|
218
|
+
const end = options?.end !== undefined ? options.end : '';
|
|
219
|
+
params.Range = `bytes=${start}-${end}`;
|
|
220
|
+
}
|
|
221
|
+
const result = await s3.send(new GetObjectCommand(params));
|
|
221
222
|
// @ts-ignore
|
|
222
223
|
return result.Body as Readable;
|
|
223
224
|
}
|
|
@@ -121,16 +121,7 @@ export class IntegrationProfileService {
|
|
|
121
121
|
? { integration_provider: { slug: normalizedProviderSlug } }
|
|
122
122
|
: {}),
|
|
123
123
|
},
|
|
124
|
-
|
|
125
|
-
id: true,
|
|
126
|
-
slug: true,
|
|
127
|
-
name: true,
|
|
128
|
-
config: true,
|
|
129
|
-
type_id: true,
|
|
130
|
-
provider_id: true,
|
|
131
|
-
is_active: true,
|
|
132
|
-
created_at: true,
|
|
133
|
-
updated_at: true,
|
|
124
|
+
include: {
|
|
134
125
|
integration_type: {
|
|
135
126
|
select: {
|
|
136
127
|
slug: true,
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { PrismaModule } from '@hed-hog/api-prisma';
|
|
2
|
-
import { Module, forwardRef } from '@nestjs/common';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
forwardRef(() =>
|
|
12
|
-
forwardRef(() =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import { PrismaModule } from '@hed-hog/api-prisma';
|
|
2
|
+
import { Module, forwardRef } from '@nestjs/common';
|
|
3
|
+
import { AiInstructionModule } from '../ai-instruction/ai-instruction.module';
|
|
4
|
+
import { McpModule } from '../mcp/mcp.module';
|
|
5
|
+
import { SettingModule } from '../setting/setting.module';
|
|
6
|
+
import { McpChatController } from './mcp-chat.controller';
|
|
7
|
+
import { McpChatService } from './mcp-chat.service';
|
|
8
|
+
|
|
9
|
+
@Module({
|
|
10
|
+
imports: [
|
|
11
|
+
forwardRef(() => PrismaModule),
|
|
12
|
+
forwardRef(() => SettingModule),
|
|
13
|
+
forwardRef(() => McpModule),
|
|
14
|
+
forwardRef(() => AiInstructionModule),
|
|
15
|
+
],
|
|
16
|
+
controllers: [McpChatController],
|
|
17
|
+
providers: [McpChatService],
|
|
18
|
+
})
|
|
19
|
+
export class McpChatModule {}
|