( accessToken: string, siteUrl: string, startDate: string, endDate: string, dimensions: string[], dimensionFilterGroups?: GscFilterGroup[] )
| 140 | } |
| 141 | |
| 142 | async function queryGscSearchAnalytics( |
| 143 | accessToken: string, |
| 144 | siteUrl: string, |
| 145 | startDate: string, |
| 146 | endDate: string, |
| 147 | dimensions: string[], |
| 148 | dimensionFilterGroups?: GscFilterGroup[] |
| 149 | ): Promise<GscApiRow[]> { |
| 150 | const encodedSiteUrl = encodeURIComponent(siteUrl); |
| 151 | const url = `https://www.googleapis.com/webmasters/v3/sites/${encodedSiteUrl}/searchAnalytics/query`; |
| 152 | |
| 153 | const allRows: GscApiRow[] = []; |
| 154 | let startRow = 0; |
| 155 | const rowLimit = 25000; |
| 156 | |
| 157 | while (true) { |
| 158 | const res = await fetch(url, { |
| 159 | method: 'POST', |
| 160 | headers: { |
| 161 | Authorization: `Bearer ${accessToken}`, |
| 162 | 'Content-Type': 'application/json', |
| 163 | }, |
| 164 | body: JSON.stringify({ |
| 165 | startDate, |
| 166 | endDate, |
| 167 | dimensions, |
| 168 | rowLimit, |
| 169 | startRow, |
| 170 | dataState: 'all', |
| 171 | ...(dimensionFilterGroups && { dimensionFilterGroups }), |
| 172 | }), |
| 173 | }); |
| 174 | |
| 175 | if (!res.ok) { |
| 176 | const text = await res.text(); |
| 177 | throw new Error(`GSC query failed for dimensions [${dimensions.join(',')}]: ${text}`); |
| 178 | } |
| 179 | |
| 180 | const data = (await res.json()) as { rows?: GscApiRow[] }; |
| 181 | const rows = data.rows ?? []; |
| 182 | allRows.push(...rows); |
| 183 | |
| 184 | if (rows.length < rowLimit) break; |
| 185 | startRow += rowLimit; |
| 186 | } |
| 187 | |
| 188 | return allRows; |
| 189 | } |
| 190 | |
| 191 | function formatDate(date: Date): string { |
| 192 | return date.toISOString().slice(0, 10); |
no test coverage detected