fix: refine stacktrace attribution of errors thrown from middleware (#21470)

* Refine middleware types to include the method signature and to express the nullability of the middleware.

* Make sure that the stacktrace does not involve middleware unless the error originated from the middleware itself.

Co-authored-by: steveluscher <github@steveluscher.com>
This commit is contained in:
Steven Luscher 2021-11-28 21:43:33 -08:00 committed by GitHub
parent 88ef24cecb
commit d36ff8d978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 8 deletions

View File

@ -760,19 +760,24 @@ function createRpcClient(
agentManager = new AgentManager(useHttps); agentManager = new AgentManager(useHttps);
} }
let fetchWithMiddleware: (url: string, options: any) => Promise<Response>; let fetchWithMiddleware:
| ((url: string, options: any) => Promise<Response>)
| undefined;
if (fetchMiddleware) { if (fetchMiddleware) {
fetchWithMiddleware = (url: string, options: any) => { fetchWithMiddleware = async (url: string, options: any) => {
return new Promise<Response>((resolve, reject) => { const modifiedFetchArgs = await new Promise<[string, any]>(
fetchMiddleware(url, options, async (url: string, options: any) => { (resolve, reject) => {
try { try {
resolve(await fetch(url, options)); fetchMiddleware(url, options, (modifiedUrl, modifiedOptions) =>
resolve([modifiedUrl, modifiedOptions]),
);
} catch (error) { } catch (error) {
reject(error); reject(error);
} }
}); },
}); );
return await fetch(...modifiedFetchArgs);
}; };
} }
@ -1972,7 +1977,7 @@ export type HttpHeaders = {[header: string]: string};
export type FetchMiddleware = ( export type FetchMiddleware = (
url: string, url: string,
options: any, options: any,
fetch: Function, fetch: (modifiedUrl: string, modifiedOptions: any) => void,
) => void; ) => void;
/** /**

View File

@ -133,6 +133,35 @@ describe('Connection', () => {
}); });
} }
it('should attribute middleware fatals to the middleware', async () => {
let connection = new Connection(url, {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fetchMiddleware: (_url, _options, _fetch) => {
throw new Error('This middleware experienced a fatal error');
},
});
const error = await expect(connection.getVersion()).to.be.rejectedWith(
'This middleware experienced a fatal error',
);
expect(error)
.to.be.an.instanceOf(Error)
.and.to.have.property('stack')
.that.include('fetchMiddleware');
});
it('should not attribute fetch errors to the middleware', async () => {
let connection = new Connection(url, {
fetchMiddleware: (url, _options, fetch) => {
fetch(url, 'An `Object` was expected here; this is a `TypeError`.');
},
});
const error = await expect(connection.getVersion()).to.be.rejected;
expect(error)
.to.be.an.instanceOf(Error)
.and.to.have.property('stack')
.that.does.not.include('fetchMiddleware');
});
it('get account info - not found', async () => { it('get account info - not found', async () => {
const account = Keypair.generate(); const account = Keypair.generate();