auth graph
This commit is contained in:
@@ -1,30 +1,94 @@
|
||||
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
|
||||
import { FastifyReply } from 'fastify';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
|
||||
@Injectable()
|
||||
export class ResponseInterceptor implements NestInterceptor {
|
||||
//
|
||||
intercept(context: ExecutionContext, next: CallHandler<Record<string, unknown>>): Observable<unknown> {
|
||||
const ctx = context.switchToHttp().getResponse<FastifyReply>();
|
||||
const statusCode = ctx.statusCode;
|
||||
constructor(private reflector: Reflector) {}
|
||||
|
||||
return next.handle().pipe(
|
||||
map(data => {
|
||||
if (data && data.data !== undefined) {
|
||||
intercept(context: ExecutionContext, next: CallHandler<Record<string, unknown>>): Observable<unknown> {
|
||||
// Check if this is a GraphQL request
|
||||
// GraphQL requests should bypass this interceptor as they handle their own response format
|
||||
|
||||
// Method 1: Check context type (most reliable for GraphQL)
|
||||
const contextType = context.getType();
|
||||
if (contextType === 'graphql') {
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
// Method 2: Check request URL and body for GraphQL endpoint
|
||||
try {
|
||||
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
||||
// Check URL path
|
||||
if (request.url?.includes('/graphql') || request.routerPath?.includes('/graphql')) {
|
||||
return next.handle();
|
||||
}
|
||||
// Check if request body contains GraphQL query/mutation
|
||||
const body = request.body as any;
|
||||
if (body && typeof body === 'object' && (body.query || body.mutation || body.operationName)) {
|
||||
return next.handle();
|
||||
}
|
||||
} catch {
|
||||
// Not an HTTP context, might be GraphQL - skip wrapping
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
// Method 3: Check if handler is a GraphQL resolver by checking the class name
|
||||
const handler = context.getHandler();
|
||||
const className = context.getClass()?.name || '';
|
||||
const handlerName = handler?.name || '';
|
||||
if (className.includes('Resolver') || handlerName.includes('Resolver')) {
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
// Method 4: Try to create GraphQL context - if it doesn't throw, it's GraphQL
|
||||
try {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
// If we can create it and it has GraphQL-specific properties, it's GraphQL
|
||||
if (gqlContext && gqlContext.getInfo) {
|
||||
return next.handle();
|
||||
}
|
||||
} catch {
|
||||
// Not a GraphQL context, continue
|
||||
}
|
||||
|
||||
// For REST endpoints, wrap the response
|
||||
try {
|
||||
const ctx = context.switchToHttp().getResponse<FastifyReply>();
|
||||
const statusCode = ctx.statusCode;
|
||||
|
||||
// If statusCode is undefined, it might be a GraphQL request - skip wrapping
|
||||
if (statusCode === undefined) {
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
return next.handle().pipe(
|
||||
map(data => {
|
||||
// If data is already wrapped or doesn't need wrapping, return as-is
|
||||
if (data && typeof data === 'object' && 'data' in data && 'success' in data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (data && data.data !== undefined) {
|
||||
return {
|
||||
statusCode,
|
||||
success: true,
|
||||
data: data.data,
|
||||
};
|
||||
}
|
||||
return {
|
||||
statusCode,
|
||||
success: true,
|
||||
data: data.data,
|
||||
data,
|
||||
};
|
||||
}
|
||||
return {
|
||||
statusCode,
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
// If we can't get HTTP context either, return data as-is (likely GraphQL)
|
||||
return next.handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user