The createWindowEndpoint adapter requires a non-wildcard expectedOrigin. Every inbound MessageEvent is validated against this origin before decoding:
import { createWindowEndpoint } from "postwire";
// CORRECT — explicit expected origin
const endpoint = createWindowEndpoint(
iframe.contentWindow,
"https://embed.example.com"
);
// WRONG — wildcard is refused at the type level
// createWindowEndpoint(iframe.contentWindow, "*"); // TypeScript errorIf a message arrives from an unexpected origin, the library drops it silently and emits an ORIGIN_REJECTED StreamError on the channel. This prevents cross-site message injection even if the page is loaded in a context that receives messages from multiple origins.
Why no wildcard? A wildcard targetOrigin is a supply-chain attack vector. Sandboxed iframes or third-party scripts in the page could inject frames that the library would process, potentially corrupting stream state. The library refuses to ship a default that accepts *.
For bulk data transfer over a cross-origin iframe, the recommended pattern is:
- Establish a
MessageChannelviapostMessagewith an explicittargetOrigin. - Hand
port2to the iframe. - Wrap
port1withcreateMessagePortEndpointon the parent side. - Wrap the received port with
createMessagePortEndpointinside the iframe.
MessagePort endpoints have no origin concept — the origin check happens at the postMessage hand-off step, which the caller controls.
The baseline path (postMessage + structured clone / transferable, no SAB, no WASM) is fully compatible with Content-Security-Policy: default-src 'self'; script-src 'self':
- No
eval() - No
new Function() - No dynamic
import()of external URLs - No inline script injection
- No
blob:ordata:URL script execution
The library bundle (tsdown-built ESM) does not generate any eval-equivalent constructs.
The SAB (SharedArrayBuffer) fast path requires cross-origin isolation — not an unsafe-eval relaxation:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
These headers isolate the page into its own agent cluster and enable SharedArrayBuffer. They do not require relaxing the script execution policy. If COOP/COEP cannot be set (e.g. third-party embeds, existing CDN content), SAB falls back to the transferable path automatically — no caller change needed.
The ./wasm entry point is reserved for a future WASM milestone. When available, the WASM path will require script-src 'wasm-unsafe-eval' as an explicit caller opt-in. The baseline path will never require it.
An iframe with sandbox="allow-scripts" (no allow-same-origin) has no access to the parent's DOM or storage. The library works correctly in this context — the MessagePort channel is handed in via postMessage before the allow-same-origin restriction matters.
SAB is unavailable in cross-origin-sandboxed iframes (different agent cluster). The library detects this via isSabCapable() and falls back automatically.
Service workers run in a different agent cluster than the controlled pages. The library's createServiceWorkerEndpoint adapter marks the endpoint as SAB-incapable. Data flows only via postMessage.
Service workers may be terminated by the browser at any time. Use options.heartbeat to detect recycling and surface CHANNEL_DEAD instead of a silent stall.
Dedicated workers share the same agent cluster as their parent page and are SAB-capable when the page is cross-origin-isolated. Shared workers and service workers are not.
- No encryption — use the caller-supplied crypto layer or rely on TLS at the transport level.
- No authentication — the library trusts the caller to establish the postMessage boundary with trusted parties.
- No origin forgery detection — the
ORIGIN_REJECTEDguard protects against receiving from wrong origins; it does not prevent a malicious page from spoofing the sender origin if the browser has a vulnerability. Trust the browser's origin isolation model.
- Endpoint adapters —
createWindowEndpointorigin parameter - Errors —
ORIGIN_REJECTED,SAB_INIT_FAILED