Multi-peer connections
A single expose() call can be reached by more than one peer: several pages connecting to one SharedWorker, several contexts on one broadcast channel. osra connects them all, but the returned promise only ever carries one value.
First peer wins
Section titled “First peer wins”The promise returned by expose() resolves with the first peer’s value. Later peers still connect, can call your exposed value, and keep their own connection state, but there is no public accessor for their values.
One expose() per port
Section titled “One expose() per port”When you need a value per peer (the SharedWorker case), expose once per port instead:
// shared-worker.tsimport { const expose: <T = unknown, const TModules extends readonly RevivableModule[] = readonly [typeof import("osra/build/revivables/transfer"), typeof import("osra/build/revivables/identity"), typeof import("osra/build/revivables/array-buffer"), typeof import("osra/build/revivables/date"), typeof import("osra/build/revivables/headers"), typeof import("osra/build/revivables/error"), ... 21 more ..., { ...;}], const TTransport extends Transport = Transport, const TValue = Capable<...>>(value: CapableCheck<...>, options: StartConnectionsOptions<TModules> & { transport: TTransport;}) => Promise<Remote<T>>
expose } from 'osra'
export const const api: { add: (a: number, b: number) => Promise<number>;}
api = { add: (a: number, b: number) => Promise<number>
add: async (a: number
a: number, b: number
b: number) => a: number
a + b: number
b }
module globalThis
globalThis.var onconnect: ((event: MessageEvent) => void) | null
onconnect = (event: MessageEvent<any>
event: interface MessageEvent<T = any>
The MessageEvent interface represents a message received by a target object.
MessageEvent) => { for (const const port: MessagePort
port of event: MessageEvent<any>
event.MessageEvent<any>.ports: readonly MessagePort[]
The ports read-only property of the containing all MessagePort objects sent with the message, in order.
ports) expose<unknown, readonly [typeof import("osra/build/revivables/transfer"), typeof import("osra/build/revivables/identity"), typeof import("osra/build/revivables/array-buffer"), typeof import("osra/build/revivables/date"), typeof import("osra/build/revivables/headers"), typeof import("osra/build/revivables/error"), typeof import("osra/build/revivables/typed-array"), ... 20 more ..., { ...;}], MessagePort, { ...;}>(value: { ...;}, options: StartConnectionsOptions<...> & { ...;}): Promise<...>
expose(const api: { add: (a: number, b: number) => Promise<number>;}
api, { transport: Transport & MessagePort
transport: const port: MessagePort
port })}// pageimport type { const api: { add: (a: number, b: number) => Promise<number>;}
api } from './shared-worker.ts'
const const worker: SharedWorker
worker = new var SharedWorker: new (scriptURL: string | URL, options?: string | WorkerOptions) => SharedWorker
The SharedWorker interface represents a specific kind of worker that can be accessed from several browsing contexts, such as several windows, iframes or even workers.
SharedWorker('./shared-worker.ts', { WorkerOptions.type?: WorkerType | undefined
type: 'module' })const const remote: { add: (a: number, b: number) => Promise<number>;}
remote = await expose<{ add: (a: number, b: number) => Promise<number>;}, readonly [typeof import("osra/build/revivables/transfer"), typeof import("osra/build/revivables/identity"), typeof import("osra/build/revivables/array-buffer"), typeof import("osra/build/revivables/date"), typeof import("osra/build/revivables/headers"), typeof import("osra/build/revivables/error"), ... 21 more ..., { ...;}], Transport, Capable<...>>(value: Capable<...>, options: StartConnectionsOptions<...> & { ...;}): Promise<...>
expose<typeof const api: { add: (a: number, b: number) => Promise<number>;}
api>({}, { transport: Transport
transport: const worker: SharedWorker
worker })The page passes the SharedWorker object itself; osra sends and listens on its .port (and starts it) internally. The worker side gets one expose() (and one first-wins promise) per connecting page, so each connection is isolated and each page’s value is addressable.
Bridging peers
Section titled “Bridging peers”To connect two peers that share no direct channel (two workers, or an iframe and a worker), a context that owns both transports can forward envelopes between them with relay().