( accessToken: string, config: GoogleDriveWebhookConfig, requestId: string, logger: Logger )
| 245 | } |
| 246 | |
| 247 | async function fetchChanges( |
| 248 | accessToken: string, |
| 249 | config: GoogleDriveWebhookConfig, |
| 250 | requestId: string, |
| 251 | logger: Logger |
| 252 | ): Promise<{ changes: DriveChangeEntry[]; newStartPageToken: string }> { |
| 253 | const allChanges: DriveChangeEntry[] = [] |
| 254 | let currentPageToken = config.pageToken! |
| 255 | let newStartPageToken: string | undefined |
| 256 | let lastNextPageToken: string | undefined |
| 257 | const maxFiles = config.maxFilesPerPoll || MAX_FILES_PER_POLL |
| 258 | let pages = 0 |
| 259 | |
| 260 | while (true) { |
| 261 | pages++ |
| 262 | const params = new URLSearchParams({ |
| 263 | pageToken: currentPageToken, |
| 264 | pageSize: String(Math.min(maxFiles, 100)), |
| 265 | fields: `nextPageToken,newStartPageToken,changes(kind,type,time,removed,fileId,file(${FILE_FIELDS}))`, |
| 266 | restrictToMyDrive: config.includeSharedDrives ? 'false' : 'true', |
| 267 | }) |
| 268 | |
| 269 | if (config.includeSharedDrives) { |
| 270 | params.set('supportsAllDrives', 'true') |
| 271 | params.set('includeItemsFromAllDrives', 'true') |
| 272 | } |
| 273 | |
| 274 | const url = `${DRIVE_API_BASE}/changes?${params.toString()}` |
| 275 | const response = await fetch(url, { |
| 276 | headers: { Authorization: `Bearer ${accessToken}` }, |
| 277 | }) |
| 278 | |
| 279 | if (!response.ok) { |
| 280 | const status = response.status |
| 281 | const errorData = await response.json().catch(() => ({})) |
| 282 | if (status === 410) { |
| 283 | const err = new Error('Drive page token is no longer valid') |
| 284 | err.name = 'DrivePageTokenInvalidError' |
| 285 | throw err |
| 286 | } |
| 287 | if (status === 429 || isDriveRateLimitError(status, errorData)) { |
| 288 | const err = new Error(`Drive API rate limit (${status}): ${JSON.stringify(errorData)}`) |
| 289 | err.name = 'DriveRateLimitError' |
| 290 | throw err |
| 291 | } |
| 292 | throw new Error(`Failed to fetch Drive changes: ${status} - ${JSON.stringify(errorData)}`) |
| 293 | } |
| 294 | |
| 295 | const data = await response.json() |
| 296 | const changes = (data.changes || []) as DriveChangeEntry[] |
| 297 | allChanges.push(...changes) |
| 298 | |
| 299 | if (data.newStartPageToken) { |
| 300 | newStartPageToken = data.newStartPageToken as string |
| 301 | } |
| 302 | |
| 303 | const hasMore = !!data.nextPageToken |
| 304 | const overLimit = allChanges.length >= maxFiles |
no test coverage detected