Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat frontend api refactor #24

Merged
merged 32 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
47bf8ff
chore: adding tmuxinator config
Sma1lboy Oct 22, 2024
bb7478a
chore: Add tmuxinator config and support for watching codegen and dev…
Sma1lboy Oct 22, 2024
7f7a682
feat: Add support for JWT authentication in the auth module
Sma1lboy Oct 22, 2024
2fd07ab
chore: remove some code
Sma1lboy Oct 22, 2024
ff0011c
chore: Update environment variables and dependencies
Sma1lboy Oct 22, 2024
7afa251
Merge branch 'main' into feat-frontend-api-refactor
Sma1lboy Oct 26, 2024
ac9c5a2
chore: adding spec test rather then test
Sma1lboy Oct 26, 2024
a034248
chore: fix some bug
Sma1lboy Oct 26, 2024
666d159
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 26, 2024
ffbe0dd
Refactor project frontend API and fix backend project API
Sma1lboy Oct 26, 2024
9c1924e
Refactor frontend chat components and fix voice input functionality
Sma1lboy Oct 26, 2024
d90bf48
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 26, 2024
72209ba
refactor: improve code organization and fix voice input bug
Sma1lboy Oct 26, 2024
4902e36
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 26, 2024
2314719
refactor: improve code organization and fix voice input bug
Sma1lboy Oct 26, 2024
f2575a3
Refactor code organization and fix voice input bug
Sma1lboy Oct 29, 2024
42c7a88
refactor: improve code organization and fix voice input bug
Sma1lboy Oct 29, 2024
652c9b5
Refactor CSS variables for color scheme in globals.css
Sma1lboy Oct 29, 2024
73a810d
Merge branch 'main' into feat-frontend-api-refactor
Sma1lboy Oct 29, 2024
ce340f5
refactor: Exclude database.sqlite from version control
Sma1lboy Oct 29, 2024
806894b
refactor: Update GraphQL import in useAuth.ts
Sma1lboy Oct 29, 2024
3729eb7
refactor: Exclude database.sqlite from version control
Sma1lboy Oct 29, 2024
bb28f69
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 29, 2024
ff17f54
refactor: Update GraphQL import in useAuth.ts
Sma1lboy Oct 29, 2024
d07ef4c
chore: change client dir
Sma1lboy Oct 29, 2024
fb4319f
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 29, 2024
a2310f7
refactor: Update import statements for decorators in chat.resolver.ts
Sma1lboy Oct 29, 2024
eb8ccca
refactor: Update import statements for decorators in chat.resolver.ts
Sma1lboy Oct 29, 2024
d89f771
refactor: Update import statements for decorators in chat.resolver.ts
Sma1lboy Oct 29, 2024
abd7b81
refactor: Update import statements for decorators in chat.resolver.ts
Sma1lboy Oct 29, 2024
723a6e4
refactor: Update import statements for decorators in chat.resolver.ts
Sma1lboy Oct 29, 2024
6279339
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {

Check failure on line 1 in .eslintrc.js

View workflow job for this annotation

GitHub Actions / autofix

'module' is not defined
root: true,
parser: '@typescript-eslint/parser',
extends: [
Expand All @@ -19,5 +19,6 @@
'no-console': 'warn',
'prefer-const': 'error',
'no-var': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding explicit return types rule.

Since you're enhancing TypeScript support, consider also adding the @typescript-eslint/explicit-function-return-type rule to ensure all functions have explicit return types.

     '@typescript-eslint/no-explicit-any': 'warn',
+    '@typescript-eslint/explicit-function-return-type': ['error', {
+      allowExpressions: true,
+      allowTypedFunctionExpressions: true,
+    }],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': ['error', {
allowExpressions: true,
allowTypedFunctionExpressions: true,
}],

},
};
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ dist/

# Models
models/
*/**/models/
*/**/models/

*/**/database.sqlite
./backend/src/database.sqlite
4 changes: 4 additions & 0 deletions .vscode/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"cSpell.words": ["upsert"]
}
33 changes: 33 additions & 0 deletions backend/interceptor/LoggingInterceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
Logger,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { GqlExecutionContext } from '@nestjs/graphql';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger('GraphQLRequest');

intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const ctx = GqlExecutionContext.create(context);
const { operation, fieldName } = ctx.getInfo();
let variables = '';
try {
variables = ctx.getContext().req.body.variables;
} catch (error) {

Check warning on line 21 in backend/interceptor/LoggingInterceptor.ts

View workflow job for this annotation

GitHub Actions / autofix

'error' is defined but never used
variables = '';
}
Comment on lines +19 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling in variable extraction.

The current implementation silently fails and sets variables to an empty string, which might hide important debugging information.

Apply this diff to improve error handling:

    try {
      variables = ctx.getContext().req.body.variables;
    } catch (error) {
-     variables = '';
+     this.logger.warn(
+       `Failed to extract variables: ${error.message}`,
+       error.stack,
+     );
+     variables = undefined;
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
variables = ctx.getContext().req.body.variables;
} catch (error) {
variables = '';
}
try {
variables = ctx.getContext().req.body.variables;
} catch (error) {
this.logger.warn(
`Failed to extract variables: ${error.message}`,
error.stack,
);
variables = undefined;
}
🧰 Tools
🪛 GitHub Check: autofix

[warning] 21-21:
'error' is defined but never used


this.logger.log(
`${operation.operation.toUpperCase()} \x1B[33m${fieldName}\x1B[39m${
variables ? ` Variables: ${JSON.stringify(variables)}` : ''
}`,
);
Comment on lines +25 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance logging implementation with security and maintainability improvements.

Several suggestions to improve the logging implementation:

  1. Sanitize sensitive information in variables before logging
  2. Consider removing ANSI color codes for better log parsing
  3. Add request timing information for performance monitoring

Here's an improved implementation:

-    this.logger.log(
-      `${operation.operation.toUpperCase()} \x1B[33m${fieldName}\x1B[39m${
-        variables ? ` Variables: ${JSON.stringify(variables)}` : ''
-      }`,
-    );
+    const sanitizedVariables = this.sanitizeVariables(variables);
+    const startTime = Date.now();
+    
+    this.logger.log({
+      type: operation.operation.toUpperCase(),
+      field: fieldName,
+      variables: sanitizedVariables,
+      timestamp: new Date().toISOString()
+    });
+
+    return next.handle().pipe(
+      tap(() => {
+        const duration = Date.now() - startTime;
+        this.logger.log(`Operation completed in ${duration}ms`);
+      })
+    );

// Add this method to the class
private sanitizeVariables(variables: any): any {
  if (!variables) return undefined;
  
  const sensitiveFields = ['password', 'token', 'secret'];
  return Object.entries(variables).reduce((acc, [key, value]) => {
    acc[key] = sensitiveFields.includes(key.toLowerCase()) ? '[REDACTED]' : value;
    return acc;
  }, {});
}

Committable suggestion was skipped due to low confidence.


return next.handle();
}
Comment on lines +31 to +32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding request timing and error handling to the response pipeline.

The current implementation doesn't track request completion or handle errors in the response pipeline.

-    return next.handle();
+    return next.handle().pipe(
+      tap({
+        error: (error) => {
+          this.logger.error(
+            `Operation failed: ${error.message}`,
+            error.stack
+          );
+        }
+      })
+    );

Committable suggestion was skipped due to low confidence.

}
3 changes: 3 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@
"class-validator": "^0.14.1",
"fs-extra": "^11.2.0",
"graphql": "^16.9.0",
"graphql-subscriptions": "^2.0.0",
"graphql-ws": "^5.16.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"sqlite3": "^5.1.7",
"subscriptions-transport-ws": "^0.11.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

⚠️ Potential issue

Remove subscriptions-transport-ws as it's redundant with graphql-ws

The codebase is already properly configured to use the modern graphql-ws package:

  • Frontend uses GraphQLWsLink with graphql-ws client
  • Backend has graphql-ws support enabled
  • subscriptions-transport-ws is only added as a fallback but not actively used

You can safely:

  1. Remove "subscriptions-transport-ws" from backend/package.json
  2. Remove the 'subscriptions-transport-ws': true line from backend/src/app.module.ts
🔗 Analysis chain

Consider removing subscriptions-transport-ws.

The subscriptions-transport-ws package is deprecated and has known security vulnerabilities. Consider using only graphql-ws as it's the modern, maintained alternative.

Let's verify if we can safely remove this dependency:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if any files are still using subscriptions-transport-ws
rg -l "subscriptions-transport-ws"

# Check for specific usage of the legacy protocol
ast-grep --pattern 'transport: "ws"'

Length of output: 204


Script:

#!/bin/bash
# Let's check the actual usage in app.module.ts and look for any subscription setup
rg -A 10 "subscriptions-transport-ws" backend/src/app.module.ts

# Also check for any GraphQL subscription setup patterns
ast-grep --pattern 'GraphQLModule.forRoot({
  $$$
})'

# Check if graphql-ws is also present
rg -l "graphql-ws"

Length of output: 619


Script:

#!/bin/bash
# Let's check the GraphQL client setup in frontend
rg -A 10 "graphql-ws" frontend/src/lib/client.ts

# Check if there are any WebSocket transport configurations
rg -A 5 "WebSocketLink|wsLink" frontend/src/lib/client.ts

# Check the complete GraphQL module configuration
rg -A 15 "GraphQLModule.forRoot" backend/src/app.module.ts

Length of output: 1380

"typeorm": "^0.3.20"
},
"devDependencies": {
Expand Down
18 changes: 14 additions & 4 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,31 @@
import { TokenModule } from './token/token.module';
import { UserModule } from './user/user.module';
import { InitModule } from './init/init.module';
import { RolesGuard } from './guard/roles.guard';

Check warning on line 13 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'RolesGuard' is defined but never used. Allowed unused vars must match /^_/u
import { MenuGuard } from './guard/menu.guard';

Check warning on line 14 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'MenuGuard' is defined but never used. Allowed unused vars must match /^_/u
import { User } from './user/user.model';
import { AppResolver } from './app.resolver';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from 'interceptor/LoggingInterceptor';

@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
autoSchemaFile: join(process.cwd(), '../frontend/src/graphql/schema.gql'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Schema file location creates deployment risks and tight coupling

The verification confirms the architectural concerns. The only cross-directory reference is the schema path in app.module.ts, while other frontend/backend mentions in package.json and protocol.ts are unrelated (script names and type definitions). This schema path configuration:

  1. Creates a hard dependency on frontend directory structure
  2. Uses unreliable process.cwd() with relative path
  3. Violates separation of concerns between frontend and backend
  4. May break in containerized or CI environments

Recommended solution:

-      autoSchemaFile: join(process.cwd(), '../frontend/src/graphql/schema.gql'),
+      autoSchemaFile: join(process.cwd(), 'src/schema.gql'),

Then implement one of these approaches:

  • Add a build step to copy schema to frontend
  • Use a shared directory between services
  • Implement schema registry pattern
🔗 Analysis chain

Consider architectural implications of schema location.

Moving the GraphQL schema file to the frontend directory creates a tight coupling between backend and frontend, which could lead to deployment and build issues. This approach:

  1. Assumes a specific directory structure
  2. May fail if the frontend directory is not available
  3. Could break in containerized environments
  4. Creates a direct dependency between backend and frontend

Consider these alternatives:

  1. Keep the schema in the backend and copy it to frontend during build:
-      autoSchemaFile: join(process.cwd(), '../frontend/src/graphql/schema.gql'),
+      autoSchemaFile: join(process.cwd(), 'src/schema.gql'),

Then add a build step to copy the schema to frontend.

  1. Use a shared directory for common files:
-      autoSchemaFile: join(process.cwd(), '../frontend/src/graphql/schema.gql'),
+      autoSchemaFile: join(process.cwd(), '../shared/schema.gql'),
  1. Use schema registry or version control to manage schema separately.

Let's verify the potential impact:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any direct imports or references between frontend and backend
rg -g '!node_modules' -l 'frontend|backend' backend/

Length of output: 130


Script:

#!/bin/bash
# Let's check the content of these files to understand the nature of frontend/backend references
echo "=== app.module.ts ==="
cat backend/src/app.module.ts

echo -e "\n=== protocol.ts ==="
cat backend/src/chat/protocol.ts

echo -e "\n=== package.json ==="
cat backend/package.json

Length of output: 8602

sortSchema: true,
playground: true,
installSubscriptionHandlers: true,
subscriptions: {
'graphql-ws': true,
'subscriptions-transport-ws': true,
},
context: ({ req, res }) => ({ req, res }),
}),
TypeOrmModule.forRoot({
type: 'sqlite',
database: join(process.cwd(), 'src/database.sqlite'),
synchronize: true,
logging: true,
entities: [__dirname + '/**/*.model{.ts,.js}'],
}),
InitModule,
Expand All @@ -41,6 +45,12 @@
ChatModule,
TypeOrmModule.forFeature([User]),
],
providers: [AppResolver],
providers: [
AppResolver,
{
provide: APP_INTERCEPTOR,
useClass: LoggingInterceptor,
},
],
})
export class AppModule {}
8 changes: 4 additions & 4 deletions backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

async login(
loginUserInput: LoginUserInput,
): Promise<{ access_token: string }> {
): Promise<{ accessToken: string }> {
const { username, password } = loginUserInput;

const user = await this.userRepository.findOne({
Expand All @@ -73,10 +73,10 @@
}

const payload = { userId: user.id, username: user.username };
const access_token = this.jwtService.sign(payload);
this.jwtCacheService.storeToken(access_token);
const accessToken = this.jwtService.sign(payload);
this.jwtCacheService.storeToken(accessToken);
Comment on lines +76 to +77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider enhancing token management configuration.

While the current implementation is functional, consider these improvements:

  1. Make the JWT token expiration time configurable via ConfigService
  2. Add structured error logging in the validateToken method

Here's a suggested implementation:

 const payload = { userId: user.id, username: user.username };
-const accessToken = this.jwtService.sign(payload);
+const accessToken = this.jwtService.sign(payload, {
+  expiresIn: this.configService.get('JWT_EXPIRATION', '1h'),
+});

And in the validateToken method:

 try {
   await this.jwtService.verifyAsync(params.token);
   return this.jwtCacheService.isTokenStored(params.token);
 } catch (error) {
-  console.log(error);
+  Logger.error('Token validation failed', {
+    error: error.message,
+    token: params.token.substring(0, 10) + '...',
+  });
   return false;
 }

Committable suggestion was skipped due to low confidence.


return { access_token };
return { accessToken };
}

async validateToken(params: CheckTokenInput): Promise<boolean> {
Expand All @@ -84,7 +84,7 @@
await this.jwtService.verifyAsync(params.token);
return this.jwtCacheService.isTokenStored(params.token);
} catch (error) {
console.log(error);

Check warning on line 87 in backend/src/auth/auth.service.ts

View workflow job for this annotation

GitHub Actions / autofix

Unexpected console statement
return false;
}
}
Expand All @@ -92,7 +92,7 @@
Logger.log('logout token', token);
try {
await this.jwtService.verifyAsync(token);
} catch (error) {

Check warning on line 95 in backend/src/auth/auth.service.ts

View workflow job for this annotation

GitHub Actions / autofix

'error' is defined but never used
return false;
}

Expand Down
38 changes: 27 additions & 11 deletions backend/src/chat/chat.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ import { Message } from 'src/chat/message.model';
import { SystemBaseModel } from 'src/system-base-model/system-base.model';
import { User } from 'src/user/user.model';

export enum StreamStatus {
STREAMING = 'streaming',
DONE = 'done',
}

registerEnumType(StreamStatus, {
name: 'StreamStatus',
});

@Entity()
@ObjectType()
export class Chat extends SystemBaseModel {
Expand All @@ -44,6 +53,18 @@ class ChatCompletionDelta {
content?: string;
}

@ObjectType('ChatCompletionChoiceType')
class ChatCompletionChoice {
@Field()
index: number;

@Field(() => ChatCompletionDelta)
delta: ChatCompletionDelta;

@Field({ nullable: true })
finishReason: string | null;
}

@ObjectType('ChatCompletionChunkType')
export class ChatCompletionChunk {
@Field()
Expand All @@ -59,20 +80,15 @@ export class ChatCompletionChunk {
model: string;

@Field({ nullable: true })
system_fingerprint: string | null;
systemFingerprint: string | null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Update required: Inconsistent field naming across the codebase

The field rename from system_fingerprint to systemFingerprint is incomplete. Found inconsistencies in:

  • llm-server/src/protocol.ts: Uses system_fingerprint
  • backend/src/chat/protocol.ts: Uses system_fingerprint

While the model and frontend use camelCase, protocol files still use snake_case, which needs to be synchronized.

🔗 Analysis chain

Verify the impact of the systemFingerprint rename.

The field rename from system_fingerprint to systemFingerprint looks good, but we should verify that all consumers of this field have been updated.

Also applies to: 88-90

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining snake_case usage of system_fingerprint
rg -l "system_fingerprint" --type ts --type tsx

# Search for GraphQL queries/mutations using the old field name
rg -l "system_fingerprint" --type graphql

Length of output: 149


Script:

#!/bin/bash
# Search for any remaining snake_case usage of system_fingerprint in all files
rg "system_fingerprint"

# Search for camelCase usage to understand the context
rg "systemFingerprint"

Length of output: 666


@Field(() => [ChatCompletionChoice])
choices: ChatCompletionChoice[];
}

@ObjectType('ChatCompletionChoiceType')
class ChatCompletionChoice {
@Field()
index: number;

@Field(() => ChatCompletionDelta)
delta: ChatCompletionDelta;
@Field(() => StreamStatus)
status: StreamStatus;
}

@Field({ nullable: true })
finish_reason: string | null;
export function isDoneStatus(chunk: ChatCompletionChunk): boolean {
return chunk.status === StreamStatus.DONE;
Comment on lines +92 to +93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider making the status check more flexible.

While the current implementation works, consider making it more flexible to handle different status checks.

-export function isDoneStatus(chunk: ChatCompletionChunk): boolean {
-  return chunk.status === StreamStatus.DONE;
+export function hasStatus(chunk: ChatCompletionChunk, status: StreamStatus): boolean {
+  return chunk.status === status;
+}
+
+export const isDoneStatus = (chunk: ChatCompletionChunk): boolean => 
+  hasStatus(chunk, StreamStatus.DONE);

This approach allows for more reusability while maintaining the existing functionality.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function isDoneStatus(chunk: ChatCompletionChunk): boolean {
return chunk.status === StreamStatus.DONE;
export function hasStatus(chunk: ChatCompletionChunk, status: StreamStatus): boolean {
return chunk.status === status;
}
export const isDoneStatus = (chunk: ChatCompletionChunk): boolean =>
hasStatus(chunk, StreamStatus.DONE);

}
5 changes: 5 additions & 0 deletions backend/src/chat/chat.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Message } from 'src/chat/message.model';
import { ChatGuard } from '../guard/chat.guard';
import { AuthModule } from '../auth/auth.module';
import { UserService } from 'src/user/user.service';
import { PubSub } from 'graphql-subscriptions';

@Module({
imports: [
Expand All @@ -24,6 +25,10 @@ import { UserService } from 'src/user/user.service';
ChatService,
ChatGuard,
UserService,
{
provide: 'PUB_SUB',
useValue: new PubSub(),
},
],
exports: [ChatService, ChatGuard],
})
Expand Down
Loading
Loading