mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 09:13:33 +00:00
[EC-598] feat: add ability to throw errors across messenger
This commit is contained in:
@@ -14,6 +14,7 @@ export enum MessageType {
|
|||||||
CredentialGetResponse,
|
CredentialGetResponse,
|
||||||
AbortRequest,
|
AbortRequest,
|
||||||
AbortResponse,
|
AbortResponse,
|
||||||
|
ErrorResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CredentialCreationRequest = {
|
export type CredentialCreationRequest = {
|
||||||
@@ -43,6 +44,11 @@ export type AbortRequest = {
|
|||||||
abortedRequestId: string;
|
abortedRequestId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ErrorResponse = {
|
||||||
|
type: MessageType.ErrorResponse;
|
||||||
|
error: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type AbortResponse = {
|
export type AbortResponse = {
|
||||||
type: MessageType.AbortResponse;
|
type: MessageType.AbortResponse;
|
||||||
abortedRequestId: string;
|
abortedRequestId: string;
|
||||||
@@ -54,4 +60,5 @@ export type Message =
|
|||||||
| CredentialGetRequest
|
| CredentialGetRequest
|
||||||
| CredentialGetResponse
|
| CredentialGetResponse
|
||||||
| AbortRequest
|
| AbortRequest
|
||||||
| AbortResponse;
|
| AbortResponse
|
||||||
|
| ErrorResponse;
|
||||||
|
|||||||
@@ -44,6 +44,17 @@ describe("Messenger", () => {
|
|||||||
expect(returned).toMatchObject(response);
|
expect(returned).toMatchObject(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should throw error from B when sending request from A that fails", async () => {
|
||||||
|
const request = createRequest();
|
||||||
|
const error = new Error("Test error");
|
||||||
|
const requestPromise = messengerA.request(request);
|
||||||
|
const received = handlerB.recieve();
|
||||||
|
|
||||||
|
received[0].reject(error);
|
||||||
|
|
||||||
|
await expect(requestPromise).rejects.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
it("should deliver abort signal to B when requesting abort", () => {
|
it("should deliver abort signal to B when requesting abort", () => {
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
messengerA.request(createRequest(), abortController);
|
messengerA.request(createRequest(), abortController);
|
||||||
@@ -53,15 +64,6 @@ describe("Messenger", () => {
|
|||||||
|
|
||||||
expect(received[0].abortController.signal.aborted).toBe(true);
|
expect(received[0].abortController.signal.aborted).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip("should abort request and throw error when abort is requested from A", () => {
|
|
||||||
const abortController = new AbortController();
|
|
||||||
const requestPromise = messengerA.request(createRequest(), abortController);
|
|
||||||
|
|
||||||
abortController.abort();
|
|
||||||
|
|
||||||
expect(requestPromise).toThrow();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
type TestMessage = Message & { testId: string };
|
type TestMessage = Message & { testId: string };
|
||||||
@@ -105,6 +107,7 @@ class TestMessageHandler {
|
|||||||
private recievedMessages: {
|
private recievedMessages: {
|
||||||
message: TestMessage;
|
message: TestMessage;
|
||||||
respond: (response: TestMessage) => void;
|
respond: (response: TestMessage) => void;
|
||||||
|
reject: (error: Error) => void;
|
||||||
abortController?: AbortController;
|
abortController?: AbortController;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
@@ -115,6 +118,7 @@ class TestMessageHandler {
|
|||||||
message,
|
message,
|
||||||
abortController,
|
abortController,
|
||||||
respond: (response) => resolve(response),
|
respond: (response) => resolve(response),
|
||||||
|
reject: (error) => reject(error),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,15 +49,26 @@ export class Messenger {
|
|||||||
|
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
this.abortControllers.set(message.metadata.requestId, abortController);
|
this.abortControllers.set(message.metadata.requestId, abortController);
|
||||||
const handlerResponse = await this.handler(message, abortController);
|
|
||||||
this.abortControllers.delete(message.metadata.requestId);
|
|
||||||
|
|
||||||
if (handlerResponse === undefined) {
|
try {
|
||||||
return;
|
const handlerResponse = await this.handler(message, abortController);
|
||||||
|
|
||||||
|
if (handlerResponse === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata: Metadata = { requestId: message.metadata.requestId };
|
||||||
|
this.channel.postMessage({ ...handlerResponse, metadata });
|
||||||
|
} catch (error) {
|
||||||
|
const metadata: Metadata = { requestId: message.metadata.requestId };
|
||||||
|
this.channel.postMessage({
|
||||||
|
type: MessageType.ErrorResponse,
|
||||||
|
metadata,
|
||||||
|
error: JSON.stringify(error, Object.getOwnPropertyNames(error)),
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
this.abortControllers.delete(message.metadata.requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata: Metadata = { requestId: message.metadata.requestId };
|
|
||||||
this.channel.postMessage({ ...handlerResponse, metadata });
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.subscribe();
|
.subscribe();
|
||||||
@@ -71,7 +82,7 @@ export class Messenger {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
request(request: Message, abortController?: AbortController): Promise<Message> {
|
async request(request: Message, abortController?: AbortController): Promise<Message> {
|
||||||
const requestId = Date.now().toString();
|
const requestId = Date.now().toString();
|
||||||
const metadata: Metadata = { requestId };
|
const metadata: Metadata = { requestId };
|
||||||
|
|
||||||
@@ -93,8 +104,15 @@ export class Messenger {
|
|||||||
|
|
||||||
this.channel.postMessage({ ...request, metadata });
|
this.channel.postMessage({ ...request, metadata });
|
||||||
|
|
||||||
return promise.finally(() =>
|
const response = await promise;
|
||||||
abortController?.signal.removeEventListener("abort", abortListener)
|
abortController?.signal.removeEventListener("abort", abortListener);
|
||||||
);
|
|
||||||
|
if (response.type === MessageType.ErrorResponse) {
|
||||||
|
const error = new Error();
|
||||||
|
Object.assign(error, JSON.parse(response.error));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user