* 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, )
| 311 | * push and the watcher retries on the next edit. |
| 312 | */ |
| 313 | async function fetchTeamMemoryHashes( |
| 314 | state: SyncState, |
| 315 | repoSlug: string, |
| 316 | ): Promise<TeamMemoryHashesResult> { |
| 317 | try { |
| 318 | const session = await getAuthRuntime().resolveSession({ allowRefresh: true }) |
| 319 | const auth = getAuthHeaders(session) |
| 320 | if (auth.error) { |
| 321 | return { success: false, error: auth.error, errorType: 'auth' } |
| 322 | } |
| 323 | |
| 324 | const endpoint = getTeamMemorySyncEndpoint(repoSlug) + '&view=hashes' |
| 325 | const response = await axios.get(endpoint, { |
| 326 | headers: auth.headers, |
| 327 | timeout: TEAM_MEMORY_SYNC_TIMEOUT_MS, |
| 328 | validateStatus: status => status === 200 || status === 404, |
| 329 | }) |
| 330 | |
| 331 | if (response.status === 404) { |
| 332 | state.lastKnownChecksum = null |
| 333 | return { success: true, entryChecksums: {} } |
| 334 | } |
| 335 | |
| 336 | const checksum = |
| 337 | response.data?.checksum || response.headers['etag']?.replace(/^"|"$/g, '') |
| 338 | const entryChecksums = response.data?.entryChecksums |
| 339 | |
| 340 | // Requires anthropic/anthropic#283027. If entryChecksums is missing, |
| 341 | // treat as a probe failure — caller fails the push; watcher retries. |
| 342 | if (!entryChecksums || typeof entryChecksums !== 'object') { |
| 343 | return { |
| 344 | success: false, |
| 345 | error: |
| 346 | 'Server did not return entryChecksums (?view=hashes unsupported)', |
| 347 | errorType: 'parse', |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | if (checksum) { |
| 352 | state.lastKnownChecksum = checksum |
| 353 | } |
| 354 | return { |
| 355 | success: true, |
| 356 | version: response.data?.version, |
| 357 | checksum, |
| 358 | entryChecksums, |
| 359 | } |
| 360 | } catch (error) { |
| 361 | const { kind, status, message } = classifyAxiosError(error) |
| 362 | switch (kind) { |
| 363 | case 'auth': |
| 364 | return { |
| 365 | success: false, |
| 366 | error: 'Not authorized', |
| 367 | errorType: 'auth', |
| 368 | httpStatus: status, |
| 369 | } |
| 370 | case 'timeout': |
no test coverage detected