mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
fix(liveshare-protocol): release a stream whose unreadable open reached the owner
A 200 open whose body was not a JSON object threw from readable() before the abort listener was armed, so the page never sent stream-cancel and the owner held the id until its own budget expired. The unreadable-open path now cancels the id before rethrowing; the spec pins the cancel.
This commit is contained in:
1 parent
59ed57540b
commit
3a2a59a635
2 files changed
+13
-4
No files matched your search
@@ -14,7 +14,7 @@
|
||||
* {@link installViewerCarrier} runs in the browser from its own source text, so it must reference no
|
||||
* module binding: every constant and helper it needs is declared inside its body.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-experimental-liveshare-protocol/src/viewer-carrier
|
||||
* @module @deepseek-ai/dsh-experimental-liveshare-protocol
|
||||
*/
|
||||
|
||||
/** Page global naming the share one viewer page presents; the Liveshare client plugin reads it. */
|
||||
@@ -227,7 +227,7 @@ export function installViewerCarrier(options: ViewerCarrierOptions): void {
|
||||
const id = nextStreamId++
|
||||
signal.throwIfAborted()
|
||||
// Each path below sends this at most once: the abort listener only runs on abort, the final
|
||||
// block only without one, and the open paths return before either is armed.
|
||||
// block only without one, and an open that ends the stream cancels here before either is armed.
|
||||
const cancel = (): void => {
|
||||
void post({ op: 'stream-cancel', id }, endpoint).catch(() => undefined)
|
||||
}
|
||||
@@ -247,7 +247,15 @@ export function installViewerCarrier(options: ViewerCarrierOptions): void {
|
||||
// no stream for it: polling that id would only read `stream-not-found`, which looks like a lost
|
||||
// logical stream and would be re-opened forever. The frame's own code decides instead — an owner
|
||||
// refusal such as `remote-access/denied` is terminal, while a lost stream stays re-openable.
|
||||
const refusedOpen = failure(readable(opened, endpoint), endpoint)
|
||||
let openedBody: Record<string, unknown>
|
||||
try {
|
||||
openedBody = readable(opened, endpoint)
|
||||
} catch (error) {
|
||||
// A 200 answer the page cannot read reached the owner, which may already hold this stream id.
|
||||
if (opened.status === 200) cancel()
|
||||
throw error
|
||||
}
|
||||
const refusedOpen = failure(openedBody, endpoint)
|
||||
if (refusedOpen !== undefined) throw refusedOpen
|
||||
signal.addEventListener('abort', cancel, { once: true })
|
||||
try {
|
||||
|
||||
@@ -230,7 +230,8 @@ describe('viewer carrier streams', () => {
|
||||
expect(posted.map(request => request.op)).toEqual(['stream-open', 'stream-next', 'stream-cancel'])
|
||||
const empty = await readStream([{ status: 200, body: [] }])
|
||||
expect(markerOf(empty.error)).toEqual({ kind: 'carrier' })
|
||||
expect(empty.posted.map(request => request.op)).toEqual(['stream-open'])
|
||||
// The 200 open reached the owner, so a body the page cannot read still releases the stream id.
|
||||
expect(empty.posted.map(request => request.op)).toEqual(['stream-open', 'stream-cancel'])
|
||||
})
|
||||
|
||||
it('keeps an authentication refusal terminal whatever code its body carries', async () => {
|
||||
|
||||
Reference in new issue
Block a user