fix(apiproxy): cancel attachment reads during export
Response-consumer cancellation already stopped lineage reads, persistence reads, and ZIP production, but the final attachment phase called readImage without the producer signal. A slow or stalled attachment backend could therefore keep working after the browser abandoned the download and prevent the producer from settling.\n\nExtend the attachment read seam with optional cancellation, forward it through the local backend into Node's filesystem read, and preserve the abort reason rather than wrapping it as a storage failure. The exporter now passes its combined request/consumer signal to every attachment read.\n\nCover both ownership boundaries: the local-store test proves filesystem forwarding and cancellation identity, while the assembled export test cancels a reader during a pending attachment provider call. Regenerate the Cordis API catalog and paired documentation so implementers can rely on the new contract.
This commit is contained in:
@@ -213,7 +213,7 @@ export function sessionLogZipFilename(sessionId: string): string {
|
||||
* missing-session path can answer cleanly before streaming starts).
|
||||
* @param sessionId - the root session id.
|
||||
* @param includeDescendants - whether to include every subagent descendant.
|
||||
* @param signal - optional cancellation forwarded to lineage and persistence reads.
|
||||
* @param signal - optional cancellation forwarded to lineage, persistence, and attachment reads.
|
||||
* @returns the export entries in zip order.
|
||||
*/
|
||||
export async function* sessionLogZipEntries(
|
||||
@@ -259,7 +259,7 @@ export async function* sessionLogZipEntries(
|
||||
}
|
||||
for (const ref of media.values()) {
|
||||
signal?.throwIfAborted()
|
||||
const stored = await deps.attachments.readImage(ref)
|
||||
const stored = await deps.attachments.readImage(ref, signal)
|
||||
signal?.throwIfAborted()
|
||||
yield { path: mediaEntryPath(ref), data: stored.data }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user