4type GameActionParams = { 5 actionJSON: Record<string, unknown> 9type ValidationResult = { 11 actionJsonBytes: number 15 * Validate game action input sizes only (no rate limiting) 16 * Returns error message if validation fails, null if valid 17 * Used in test harness to verify limits don't break real games 19export const checkGameActionSizes = (params: GameActionParams): ValidationResult => { 20 const { actionJSON, gameRoom } = params 22 // Validate gameRoom length 23 if (gameRoom && gameRoom.length > inputLimits.gameRoomMaxChars) { 24 return { error: `gameRoom too long (max ${inputLimits.gameRoomMaxChars} chars)`, actionJsonBytes: 0 } 27 // Check total actionJSON size 28 const actionJsonStr = JSON.stringify(actionJSON) 29 const actionJsonBytes = actionJsonStr.length 31 if (actionJsonBytes > inputLimits.actionJsonMaxBytes) { 32 return { error: `Action payload too large (max ${Math.round(inputLimits.actionJsonMaxBytes / 1024)}KB)`, actionJsonBytes } 35 // Validate specific fields based on action type 36 const { playerAction, playerAlias, descriptionText, finishedTrails } = actionJSON as Record<string, unknown> 38 // playerAlias validation 39 if (playerAction === 'setPlayerAlias' && typeof playerAlias === 'string') { 40 if (playerAlias.length > inputLimits.playerAliasMaxChars) { 41 return { error: `Name too long (max ${inputLimits.playerAliasMaxChars} chars)`, actionJsonBytes } 45 // descriptionText validation 46 if (playerAction === 'submitDescription' && typeof descriptionText === 'string') { 47 if (descriptionText.length > inputLimits.descriptionTextMaxChars) { 48 return { error: `Description too long (max ${inputLimits.descriptionTextMaxChars} chars)`, actionJsonBytes } 52 // finishedTrails (drawing) validation 53 if (playerAction === 'submitDrawing' && finishedTrails) { 54 const trailsBytes = JSON.stringify(finishedTrails).length 55 if (trailsBytes > inputLimits.finishedTrailsMaxBytes) { 56 return { error: `Drawing too complex (max ${Math.round(inputLimits.finishedTrailsMaxBytes / 1024)}KB)`, actionJsonBytes } 60 return { actionJsonBytes } 64 * Validate game action input sizes (no rate limiting in stripped version) 65 * Call this at the start of the gameAction mutation 67export const validateGameActionInput = (params: GameActionParams) => { 68 const result = checkGameActionSizes(params)