/**
* WAVE Accessibility Analyzer
* API: https://wave.webaim.org/api/
* Requires API key (subscription required)
*/
export interface WAVEOptions {
/** API key (required - get from https://wave.webaim.org/api/) */
apiKey: string;
/** Report type: 1=summary, 2=detailed, 3=very detailed, 4=all (default: 2) */
reporttype?: 1 | 2 | 3 | 4;
/** Viewport width for testing (default: 1024) */
viewportwidth?: number;
}
export interface WAVEResponse {
status: {
success: boolean;
httpstatuscode: number;
};
statistics: {
pagetitle: string;
pageurl: string;
time: number;
creditsremaining: number;
allitemcount: number;
totalelements: number;
waveurl: string;
};
categories: {
error: {
description: string;
count: number;
items: Record<string, any>;
};
contrast: {
description: string;
count: number;
items: Record<string, any>;
};
alert: {
description: string;
count: number;
items: Record<string, any>;
};
};
}
export interface WAVEResult {
tool: 'wave';
success: boolean;
url: string;
errors: number;
contrast_errors: number;
alerts: number;
total_issues: number;
wave_report_url?: string;
credits_remaining?: number;
error?: string;
raw?: WAVEResponse;
}
/**
* Analyze website accessibility using WAVE API
* Note: Requires paid API key. See https://wave.webaim.org/api/
* Rate limit: Max 2 simultaneous requests
*/
export async function analyzeWAVE(
url: string,
options: WAVEOptions
): Promise<WAVEResult> {
try {
if (!options.apiKey) {
throw new Error('WAVE API key is required. Get one at https://wave.webaim.org/api/');
}
// Build API URL
const params = new URLSearchParams({
key: options.apiKey,
url,
});
if (options.reporttype) {
params.set('reporttype', options.reporttype.toString());
}
if (options.viewportwidth) {
params.set('viewportwidth', options.viewportwidth.toString());
}
const apiUrl = `https://wave.webaim.org/api/request?${params.toString()}`;
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`WAVE API error: ${response.status} ${response.statusText}`);
}
const data: WAVEResponse = await response.json();
if (!data.status.success) {
throw new Error(`WAVE analysis failed with HTTP status: ${data.status.httpstatuscode}`);
}
return {
tool: 'wave',
success: true,
url,
errors: data.categories.error.count,
contrast_errors: data.categories.contrast.count,
alerts: data.categories.alert.count,
total_issues: data.categories.error.count + data.categories.contrast.count + data.categories.alert.count,
wave_report_url: data.statistics.waveurl,
credits_remaining: data.statistics.creditsremaining,
raw: data,
};
} catch (error) {
return {
tool: 'wave',
success: false,
url,
errors: 0,
contrast_errors: 0,
alerts: 0,
total_issues: 0,
error: error instanceof Error ? error.message : String(error),
};
}
}