mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-10-06 19:57:50 +00:00
Merge pull request #1288 from BradGroux/fix/acp-teardown-write-1287
fix: contain ACP teardown write failures
This commit is contained in:
commit
3f83da36bc
2 changed files with 48 additions and 8 deletions
36
server/src/__tests__/acp-json-rpc-peer.test.ts
Normal file
36
server/src/__tests__/acp-json-rpc-peer.test.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { AcpJsonRpcPeer } from '@veritas-kanban/shared';
|
||||
|
||||
describe('ACP JSON-RPC peer writes', () => {
|
||||
it('contains transport teardown failures for detached request replies', async () => {
|
||||
const unhandled: unknown[] = [];
|
||||
const onUnhandled = (reason: unknown) => unhandled.push(reason);
|
||||
process.on('unhandledRejection', onUnhandled);
|
||||
|
||||
try {
|
||||
const peer = new AcpJsonRpcPeer({
|
||||
write: async () => {
|
||||
throw new Error('stream destroyed');
|
||||
},
|
||||
onRequest: async () => ({}),
|
||||
});
|
||||
|
||||
peer.acceptChunk('{"jsonrpc":"2.0","id":1,"method":"session/request_permission"}\n');
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
|
||||
expect(unhandled).toEqual([]);
|
||||
} finally {
|
||||
process.off('unhandledRejection', onUnhandled);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps caller-awaited write failures observable', async () => {
|
||||
const peer = new AcpJsonRpcPeer({
|
||||
write: async () => {
|
||||
throw new Error('stream destroyed');
|
||||
},
|
||||
});
|
||||
|
||||
await expect(peer.notify('session/cancel', {})).rejects.toThrow('stream destroyed');
|
||||
});
|
||||
});
|
||||
|
|
@ -76,7 +76,7 @@ export class AcpJsonRpcPeer {
|
|||
try {
|
||||
record = JSON.parse(line);
|
||||
} catch {
|
||||
void this.send(jsonRpcError(null, -32700, 'Parse error'));
|
||||
this.sendDetached(jsonRpcError(null, -32700, 'Parse error'));
|
||||
continue;
|
||||
}
|
||||
this.acceptRecord(record);
|
||||
|
|
@ -117,7 +117,7 @@ export class AcpJsonRpcPeer {
|
|||
}
|
||||
|
||||
if (typeof value.method !== 'string' || !value.method.trim()) {
|
||||
if (id !== undefined) void this.send(jsonRpcError(id, -32600, 'Invalid Request'));
|
||||
if (id !== undefined) this.sendDetached(jsonRpcError(id, -32600, 'Invalid Request'));
|
||||
return;
|
||||
}
|
||||
if (id === undefined) {
|
||||
|
|
@ -127,14 +127,18 @@ export class AcpJsonRpcPeer {
|
|||
return;
|
||||
}
|
||||
if (!this.options.onRequest) {
|
||||
void this.send(jsonRpcError(id, -32601, 'Method not found'));
|
||||
this.sendDetached(jsonRpcError(id, -32601, 'Method not found'));
|
||||
return;
|
||||
}
|
||||
void Promise.resolve(this.options.onRequest(value.method, value.params, id))
|
||||
.then((result) => this.send({ jsonrpc: '2.0', id, result: result ?? {} }))
|
||||
.catch((error) =>
|
||||
this.send(jsonRpcError(id, -32603, boundedMessage(error, 'Internal error')))
|
||||
);
|
||||
void Promise.resolve(this.options.onRequest(value.method, value.params, id)).then(
|
||||
(result) => this.sendDetached({ jsonrpc: '2.0', id, result: result ?? {} }),
|
||||
(error) =>
|
||||
this.sendDetached(jsonRpcError(id, -32603, boundedMessage(error, 'Internal error')))
|
||||
);
|
||||
}
|
||||
|
||||
private sendDetached(record: AcpJsonRpcMessage): void {
|
||||
void this.send(record).catch(() => undefined);
|
||||
}
|
||||
|
||||
private send(record: AcpJsonRpcMessage): Promise<void> {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue