Browser Adapter
Use oRPC for typesafe communication between browser scripts via the Message Port Adapter.
Enable typesafe communication between browser scripts using the Message Port Adapter.
Between Extension Scripts
To set up communication between scripts in a browser extension (e.g. background, content, popup), configure one script to listen for connections and upgrade them, and another to initiate the connection.
import { onError } from '@orpc/server'
import { RPCHandler } from '@orpc/server/message-port'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
browser.runtime.onConnect.addListener((port) => {
handler.upgrade(port, {
context: {} // Provide initial context if needed
})
})import { RPCLink } from '@orpc/client/message-port'
const port = browser.runtime.connect()
const link = new RPCLink({
port,
})Window to Window
To enable communication between two window contexts (e.g. parent and popup), one must listen and upgrade the port, and the other must initiate the connection.
import { onError } from '@orpc/server'
import { RPCHandler } from '@orpc/server/message-port'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
window.addEventListener('message', (event) => {
if (event.data instanceof MessagePort) {
handler.upgrade(event.data, {
context: {} // Provide initial context if needed
})
event.data.start()
}
})
window.open('/example/popup', 'popup', 'width=680,height=520')import { RPCLink } from '@orpc/client/message-port'
const { port1: serverPort, port2: clientPort } = new MessageChannel()
window.opener.postMessage(serverPort, '*', [serverPort])
const link = new RPCLink({
port: clientPort,
})
clientPort.start()Advanced Relay Pattern
In some advanced cases, direct communication between scripts isn’t possible. For example, a content script running in the “MAIN” world cannot directly communicate with the background script using browser.runtime or chrome.runtime APIs.
To work around this, you can use a relay pattern: an additional content script running in the “ISOLATED” (default) world relays messages between the two contexts, enabling communication where direct access is restricted.
window.addEventListener('message', (event) => {
if (event.data instanceof MessagePort) {
const port = browser.runtime.connect()
// Relay `message` and `close/disconnect` events between the MessagePort and runtime.Port
event.data.addEventListener('message', (event) => {
port.postMessage(event.data)
})
event.data.addEventListener('close', () => {
port.disconnect()
})
port.onMessage.addListener((message) => {
event.data.postMessage(message)
})
port.onDisconnect.addListener(() => {
event.data.close()
})
event.data.start()
}
})import { onError } from '@orpc/server'
import { RPCHandler } from '@orpc/server/message-port'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
browser.runtime.onConnect.addListener((port) => {
handler.upgrade(port, {
context: {} // Provide initial context if needed
})
})import { RPCLink } from '@orpc/client/message-port'
const { port1: serverPort, port2: clientPort } = new MessageChannel()
window.postMessage(serverPort, '*', [serverPort])
const link = new RPCLink({
port: clientPort,
})
clientPort.start()