* Fetch only per-key checksums + metadata (no entry bodies). * Used for cheap serverChecksums refresh during 412 conflict resolution — avoids * downloading ~300KB of content just to learn which keys changed. * Requires anthropic/anthropic#283027 deployed; on failure the caller fails the * push a
( state: SyncState, repoSlug: string, )
| 313 | * push and the watcher retries on the next edit. |
| 314 | */ |
| 315 | async function fetchTeamMemoryHashes( |
| 316 | state: SyncState, |
| 317 | repoSlug: string, |
| 318 | ): Promise<TeamMemoryHashesResult> { |
| 319 | try { |
| 320 | await checkAndRefreshOAuthTokenIfNeeded() |
| 321 | const auth = getAuthHeaders() |
| 322 | if (auth.error) { |
| 323 | return { success: false, error: auth.error, errorType: 'auth' } |
| 324 | } |
| 325 | |
| 326 | const endpoint = getTeamMemorySyncEndpoint(repoSlug) + '&view=hashes' |
| 327 | const response = await axios.get(endpoint, { |
| 328 | headers: auth.headers, |
| 329 | timeout: TEAM_MEMORY_SYNC_TIMEOUT_MS, |
| 330 | validateStatus: status => status === 200 || status === 404, |
| 331 | }) |
| 332 | |
| 333 | if (response.status === 404) { |
| 334 | state.lastKnownChecksum = null |
| 335 | return { success: true, entryChecksums: {} } |
| 336 | } |
| 337 | |
| 338 | const checksum = |
| 339 | response.data?.checksum || response.headers['etag']?.replace(/^"|"$/g, '') |
| 340 | const entryChecksums = response.data?.entryChecksums |
| 341 | |
| 342 | // Requires anthropic/anthropic#283027. If entryChecksums is missing, |
| 343 | // treat as a probe failure — caller fails the push; watcher retries. |
| 344 | if (!entryChecksums || typeof entryChecksums !== 'object') { |
| 345 | return { |
| 346 | success: false, |
| 347 | error: |
| 348 | 'Server did not return entryChecksums (?view=hashes unsupported)', |
| 349 | errorType: 'parse', |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | if (checksum) { |
| 354 | state.lastKnownChecksum = checksum |
| 355 | } |
| 356 | return { |
| 357 | success: true, |
| 358 | version: response.data?.version, |
| 359 | checksum, |
| 360 | entryChecksums, |
| 361 | } |
| 362 | } catch (error) { |
| 363 | const { kind, status, message } = classifyAxiosError(error) |
| 364 | switch (kind) { |
| 365 | case 'auth': |
| 366 | return { |
| 367 | success: false, |
| 368 | error: 'Not authorized', |
| 369 | errorType: 'auth', |
| 370 | httpStatus: status, |
| 371 | } |
| 372 | case 'timeout': |
no test coverage detected