If osra’s default does not fit your needs, osra support custom transports.
The custom transport interface is simplified as such in the
expose(value, options)’s options.transport parameter.
In truth though, the emit and receive functions allows a wider range of type
such as any of the platform transports allowed values.
This expanded type allows us to properly handle connections through Iframes.
For example, emit needs to window.parent.postMessage to the parent window,
while receive listens for messages on window.addEventListener('message', ...).
Expose a value to whoever connects, and get back what they exposed.
Wrap value in context to build it once per connection, which is what lets one server answer
each realm differently (scoped resolvers per app) instead of sharing one object across all of them.
A bare function stays a plain exposed endpoint, so the wrapper is what disambiguates the two.
The result is both awaitable and async-iterable: awaiting gives the first peer, iterating gives
every peer as it connects. Both hand back the same shape.
constremote=awaitexpose(resolvers, { transport }) // the first peer's value
forawait (constremoteofexpose(resolvers, { transport })) { } // every peer's value
connection decides what that shape is. Omit it and it is the peer's value, which is what expose
has always resolved to. Return whatever a connection should mean instead:
if (!allowed(peer.context.origin)) peer.context.abort?.()
}
A peer's identity is whatever the transport can observe merged over whatever the caller declared
in context. Only a window message carries a browser-set origin and source; a MessagePort message
carries neither, so a port-based server declares what it learned when it received the port.
Observed fields win over declared ones, so a declaration can never spoof a real origin.
expose({}, {
transport: Transport & {
readonly emit: Window;
readonly receive: Window &typeof globalThis;
}
transport: {
emit: Window
emit:
var window:Window&typeof globalThis
The window property of a Window object points to the window object itself.
The second argument to emit is the list of values that should be moved instead of copied. Forward it if your channel supports transfer:
If you do not pass this option, transferable values will be copied instead of moved.
Expose a value to whoever connects, and get back what they exposed.
Wrap value in context to build it once per connection, which is what lets one server answer
each realm differently (scoped resolvers per app) instead of sharing one object across all of them.
A bare function stays a plain exposed endpoint, so the wrapper is what disambiguates the two.
The result is both awaitable and async-iterable: awaiting gives the first peer, iterating gives
every peer as it connects. Both hand back the same shape.
constremote=awaitexpose(resolvers, { transport }) // the first peer's value
forawait (constremoteofexpose(resolvers, { transport })) { } // every peer's value
connection decides what that shape is. Omit it and it is the peer's value, which is what expose
has always resolved to. Return whatever a connection should mean instead:
if (!allowed(peer.context.origin)) peer.context.abort?.()
}
A peer's identity is whatever the transport can observe merged over whatever the caller declared
in context. Only a window message carries a browser-set origin and source; a MessagePort message
carries neither, so a port-based server declares what it learned when it received the port.
Observed fields win over declared ones, so a declaration can never spoof a real origin.
The window.postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.
If you ever need to connect two contexts that cannot see each other directly,
use relay() to forward osra traffic.
For example, you could forward osra traffic from a worker to an iframe.
const
constworker:Worker
worker=new
var Worker:new (scriptURL:string|URL, options?:WorkerOptions) =>Worker
The Worker interface of the Web Workers API represents a background task that can be created via script, which can send messages back to its creator.