Create
Declare `url`, `allowedOrigin`, target, sizing bounds, and whether the surface is inline or modal.
Protocol-first iframe runtime
`@crup/port` gives embedded apps a real boundary: explicit handshake, exact origin pinning, child-driven resize, event routing, and request-response-error semantics that stay readable under production pressure.
const port = createPort({
url: childUrl,
allowedOrigin: window.location.origin,
target: '#demo-root',
mode: 'inline',
minHeight: 360,
maxHeight: 620
});
await port.mount();
await port.call('system:ping');
port.send('demo:hostContext', {
workspace: 'Growth review'
});
The child stays quiet until `port:hello` arrives from the configured exact origin.
Use `emit` and `send` for non-blocking UI and workflow signals.
Use `call`, `respond`, and `reject` when the host needs a concrete answer or a real failure.
Live Lab
The controls below drive a real iframe session. Mount creates the session, ping exercises request-response, quote asks the child for domain data, context pushes a host-side event into the embedded app, and the child resize lab expands the iframe on demand.
Event Timeline
latest firstLifecycle
`@crup/port` is opinionated about the moments that usually fail first in embedded products: load timing, readiness, origin pinning, cleanup, and response correlation.
Declare `url`, `allowedOrigin`, target, sizing bounds, and whether the surface is inline or modal.
The host creates the iframe, waits for `load`, and rejects if the iframe never becomes usable.
The host sends `port:hello`; the child only responds with `port:ready` after origin validation succeeds.
Inline ports become `open` after handshake; modal ports stay hidden until you call `open()` explicitly.
Events move telemetry and UI signals. Requests and responses move data that needs a concrete result.
Outstanding calls reject, listeners are removed, and the iframe surface is torn down cleanly.
Contract Design
`port:hello`, `port:ready`, and `port:resize` are reserved for runtime behavior.
Use one-way messages for telemetry, page changes, and UI acknowledgements such as `demo:planChanged`.
Use request-response for operations that block the host on an answer, such as a quote, auth step, or snapshot.
Timeouts, invalid state, and origin mismatch are first-class failure conditions, not console folklore.
port.on('demo:planChanged', (payload) => {
console.log('child selected', payload);
});
port.send('demo:hostContext', {
workspace: 'Ops review',
accent: 'amber'
});
child.on('request:demo:getQuote', (message) => {
const request = message as { messageId: string };
child.respond(request.messageId, {
plan: 'Growth',
price: 249,
currency: 'USD'
});
});
Recipes
Mount directly into a page region and let the child control height through `resize()` events.
Open exampleKeep the iframe mounted but hidden until the user opens the experience deliberately.
Open exampleExpand the child resize lab to watch the iframe height update from an explicit `resize()` message.
Read guideHandle `request:*` messages with `respond(messageId, payload)` or `reject(messageId, payload)` instead of ad hoc reply channels.
Open exampleDocument event names, payloads, and ownership so the host and child teams do not drift independently.
Read guideDocumentation
Package overview, install commands, quick start, and doc links.
Getting StartedHost setup, child setup, modal mode, cleanup, and production checklist.
API ReferenceConfig options, methods, states, and error codes for both runtimes.
LifecycleState transitions, timing expectations, and what each phase guarantees.
Events And RPCMessage naming, payload patterns, request-response guidance, and event examples.
ProtocolEnvelope shape, system messages, routing rules, and versioning guidance.
Next Step