@stagas/rpc
v1.0.0
Published
Typed RPC for MessagePort-like transports.
Maintainers
Readme
@stagas/rpc
Typed RPC for MessagePort-like transports.
@stagas/rpc turns a bidirectional message channel into a promise-based remote
API. Pass it a port and a local API object, then call methods on the returned
proxy as if they were local async functions.
Features
- Typed remote method calls through a proxy API.
- Works with
Worker,MessagePort, and otherpostMessage-compatible ports. - Supports bidirectional RPC by giving each side its own local API.
- Automatically transfers common transferable values such as
MessagePortandOffscreenCanvas. - Allows custom transferable constructors for application-specific values.
Install
npm install @stagas/rpcbun add @stagas/rpcUsage
Define the API exposed by the worker:
// worker.ts
import { rpc } from '@stagas/rpc'
const api = {
async add(a: number, b: number) {
return a + b
},
}
rpc(self, api)Create a typed client from the main thread:
// main.ts
import { rpc } from '@stagas/rpc'
type WorkerApi = {
add(a: number, b: number): Promise<number>
}
const worker = new Worker(new URL('./worker.ts', import.meta.url), {
type: 'module',
})
const remote = rpc<WorkerApi>(worker)
const total = await remote.add(2, 3)You can also call methods by name:
const total = await remote('add', 2, 3)Bidirectional RPC
Both sides can expose methods. The same rpc call accepts a local API object and
returns a proxy for the remote API.
type ClientApi = {
notify(message: string): Promise<void>
}
type WorkerApi = {
start(): Promise<void>
}
const clientApi: ClientApi = {
async notify(message) {
console.log(message)
},
}
const worker = new Worker(new URL('./worker.ts', import.meta.url), {
type: 'module',
})
const remote = rpc<WorkerApi>(worker, clientApi)
await remote.start()Transferables
@stagas/rpc detects transferable values in call arguments and return values.
By default it transfers MessagePort and OffscreenCanvas when they are
available in the current runtime.
Pass custom constructors as the third argument when your transport should transfer additional value types:
const remote = rpc<WorkerApi>(worker, {}, [
MessagePort,
OffscreenCanvas,
])Transferable values may be passed directly or as properties of a plain object.
API
rpc<TRemote>(port, api?, transferables?)
Creates an RPC peer on top of a MessagePort-like object.
port
An object with onmessage, onmessageerror, and postMessage. Browser
workers, message ports, and compatible transports are supported.
api
An object whose function properties are exposed to the remote peer. Incoming calls reject when the requested method does not exist or is not a function.
transferables
An array of constructors used to detect values that should be sent through the structured clone transfer list.
Returns
A callable proxy that supports both property access and direct method-name calls:
await remote.someMethod(arg)
await remote('someMethod', arg)TypeScript
Declare the remote API as a method map where every method returns a promise.
type RemoteApi = {
resize(width: number, height: number): Promise<void>
snapshot(): Promise<ImageBitmap>
}
const remote = rpc<RemoteApi>(port)License
MIT
