11import { GraphQLRequestContext } from 'apollo-server-plugin-base' ;
2+ import { GraphQLError } from 'graphql' ;
23import { ResolverContextBase } from '../types/graphql' ;
34import { truncateText } from './slowOperationAlert' ;
45
6+ const MAX_ALERT_ERRORS = 10 ;
7+ const MAX_ALERT_ERRORS_LENGTH = 1200 ;
8+
59const SENSITIVE_VARIABLE_KEYS = new Set ( [
610 'password' ,
711 'token' ,
@@ -51,8 +55,15 @@ function sanitizeVariableValue(value: unknown, key: string): unknown {
5155 * @param variables - GraphQL request variables
5256 * @returns sanitized variables
5357 */
54- function sanitizeVariables ( variables : Record < string , unknown > | undefined ) : Record < string , unknown > {
55- if ( ! variables ) {
58+ function sanitizeVariables (
59+ variables : Record < string , unknown > | null | undefined
60+ ) : Record < string , unknown > {
61+ /**
62+ * Null / non-object values are treated as empty — many clients send
63+ * `variables: null` for operations without variables, and arrays are not a
64+ * valid GraphQL variables map.
65+ */
66+ if ( variables == null || typeof variables !== 'object' || Array . isArray ( variables ) ) {
5667 return { } ;
5768 }
5869
@@ -97,6 +108,23 @@ function collectHighlightedIds(
97108 return result ;
98109}
99110
111+ /**
112+ * Flatten GraphQL errors into a capped string for Hawk alert context.
113+ * sanitizeContext() only truncates top-level strings, not values nested in arrays.
114+ * Reserves space for an omitted-count suffix and truncateText()'s ellipsis.
115+ *
116+ * @param errors - GraphQL errors from the request
117+ * @returns flattened and truncated error messages
118+ */
119+ export function formatGraphqlErrorsForAlert ( errors : readonly GraphQLError [ ] ) : string {
120+ const messages = errors . slice ( 0 , MAX_ALERT_ERRORS ) . map ( ( error ) => error . message ) ;
121+ const omittedCount = errors . length - messages . length ;
122+ const omittedSuffix = omittedCount > 0 ? `; …(+${ omittedCount } more)` : '' ;
123+ const maxMessagesLength = Math . max ( 0 , MAX_ALERT_ERRORS_LENGTH - omittedSuffix . length - 1 ) ;
124+
125+ return `${ truncateText ( messages . join ( '; ' ) , maxMessagesLength ) } ${ omittedSuffix } ` ;
126+ }
127+
100128/**
101129 * Build request context for slow GraphQL operation alerts.
102130 *
@@ -105,7 +133,9 @@ function collectHighlightedIds(
105133 */
106134export function buildGraphqlRequestContext ( ctx : GraphQLRequestContext ) : Record < string , unknown > {
107135 const context = ctx . context as ResolverContextBase | undefined ;
108- const variables = sanitizeVariables ( ctx . request . variables as Record < string , unknown > | undefined ) ;
136+ const variables = sanitizeVariables (
137+ ctx . request . variables as Record < string , unknown > | null | undefined
138+ ) ;
109139 const highlightedIds = collectHighlightedIds ( variables ) ;
110140 const alertContext : Record < string , unknown > = { } ;
111141
0 commit comments