* Fetches form responses, retaining up to `MAX_RESPONSES_PER_FORM` for rendering. * Every page is scanned for the latest submission timestamp even after the * render cap is reached — the Forms API does not guarantee response order, so * the newest submission may sit on any page. `fetchLatestRespo
(accessToken: string, formId: string)
| 240 | * the listing and getDocument paths regardless of form size. |
| 241 | */ |
| 242 | async function fetchFormResponses(accessToken: string, formId: string): Promise<FetchedResponses> { |
| 243 | const collected: FormResponse[] = [] |
| 244 | let latest = '' |
| 245 | let pageToken: string | undefined |
| 246 | |
| 247 | do { |
| 248 | const url = new URL(`${FORMS_API_BASE}/forms/${encodeURIComponent(formId)}/responses`) |
| 249 | url.searchParams.set('pageSize', String(RESPONSES_PAGE_SIZE)) |
| 250 | if (pageToken) url.searchParams.set('pageToken', pageToken) |
| 251 | |
| 252 | const response = await fetchWithRetry(url.toString(), { |
| 253 | method: 'GET', |
| 254 | headers: { |
| 255 | Authorization: `Bearer ${accessToken}`, |
| 256 | Accept: 'application/json', |
| 257 | }, |
| 258 | }) |
| 259 | |
| 260 | if (!response.ok) { |
| 261 | throw new Error(`Failed to list responses for form ${formId}: ${response.status}`) |
| 262 | } |
| 263 | |
| 264 | const data = (await response.json()) as FormResponseList |
| 265 | const responses = data.responses ?? [] |
| 266 | |
| 267 | const pageLatest = latestResponseTime(responses) |
| 268 | if (pageLatest && pageLatest > latest) latest = pageLatest |
| 269 | |
| 270 | for (const r of responses) { |
| 271 | if (collected.length >= MAX_RESPONSES_PER_FORM) break |
| 272 | collected.push(r) |
| 273 | } |
| 274 | |
| 275 | pageToken = data.nextPageToken |
| 276 | } while (pageToken) |
| 277 | |
| 278 | return { responses: collected, latestSubmittedTime: latest || undefined } |
| 279 | } |
| 280 | |
| 281 | /** |
| 282 | * Reads the latest response submission time for change detection without |
no test coverage detected