A typesafe and promise-based messaging for the browser extension.
Supports Chrome, Firefox, and Safari.
Utilizes runtime.sendMessage, runtime.onMessage.addListener, and runtime.onMessageExternal.addListener.
npm install --save @vocably/hermes
The @vocably/hermes exports 2 methods: createMessage and createExternalMessage.
createMessage could be used for messaging between content script and service worker when extension ID is not necessary.
const [messageSender, messageSubscriber] = createMessage<
PayloadType,
ResponseType
>('messageIdentifier');messageSender function expects PayloadType as the only param. PayloadType could be void. Returns Promise<ResponseType>;
messageSubscriber function should be used in Service Worker to receive data of PayloadType, asynchronously process it, and return value of ResponseType.
createExternalMessage could be used for messaging between externally_connectable URLs and service worker when extension ID is necessary.
const [messageSender, messageSubscriber] = createExternalMessage<
PayloadType,
ResponseType
>('messageIdentifier');messageSender function expects extensionId: string as the first parameter and PayloadType as the second. PayloadType could be void. Returns Promise<ResponseType>;
messageSubscriber function should be used in Service Worker to receive data of PayloadType, asynchronously process it, and return value of ResponseType.
Let's imagine we need to create a user, pass it to a Service Worker and wait for the response from the Service Worker.
// save-user.ts
import { createMessage } from '@vocably/hermes';
type User = {
id?: string;
name: string;
email: string;
};
type SaveUserResponse = {
id: string;
};
export const [saveUser, onSaveUserRequest] = createMessage<
User,
SaveUserResponse
>('saveUser');// content-script.ts
import { saveUser } from './save-user.ts';
saveUser({
name: 'Speedy Gonzales',
email: 'speedy@disney.com',
}).then(({ id }) => {
console.log(`The saved user ID is ${id}`);
});// sevice-worker.ts
import { onSaveUserRequest } from './save-user.ts';
onSaveUserRequest(async (sendResponse, user) => {
let id: string;
if (user.id) {
// api.updateUser should be implemmented
// individually. It's not a part of @vocably/hermes
await api.updateUser(user);
id = user.id;
} else {
// api.createUser should be implemmented
// individually. It's not a part of @vocably/hermes
id = await api.createUser(user);
}
// The callback function must return sendResponse() with the message return value passed into it.
return sendResponse({
id,
});
});