Inter-process communication (browser)¶
Audience: Agent
This document describes the postMessage-based protocol implemented by @howfe/inter-frame-messenger and used between the surface map (parent window) and the remote journal reader (popup). Source of truth: inter-frame-messenger/src/index.ts.
Related: URL query bootstrap, embedding profiles, integration manifests (/.well-known/edos-integration.json), and optional non-IFM embed handshakes are specified in HOSTED_APP_CONTRACT.md. They are intentionally separate from MessageTypeEnum unless a maintainer adds a new enum value and coordinates all consumers (AGENTS.md).
Not IFM: Request/response access to another app’s origin-local data from a sibling iframe (for example commander bookmarks) is not a MessageTypeEnum flow. Use the composition-host proxy in HOSTED_APP_CONTRACT.md — Composition host and sibling iframes. Do not use hidden iframes to the provider origin.
Message envelope¶
All messages use the browser’s structured-clone payload shape:
| Field | Type | Meaning |
|---|---|---|
event |
string |
One of MessageTypeEnum values (e.g. 'elite-event', 'open-file:journal'). |
payload |
unknown |
Event-specific data; for elite-event / elite-status use isEliteEvent / isStatus; for edos-file-event use isEdosFileEventEnvelope (full BridgeEnvelope, same shape as desktop edos:file:event). |
Receive path: window.addEventListener('message', …) filters by event.origin (see below), then compares event.data.event to the subscribed name, then passes event.data.payload to callbacks.
Send path: target.postMessage({ event, payload }, origin) — for each origin in allowedListenerOrigins (see inter-frame-messenger/src/index.ts send implementation).
MessageTypeEnum¶
Defined in inter-frame-messenger/src/index.ts:
| Value | Direction (typical) | Payload |
|---|---|---|
elite-event |
Popup → opener | EliteEvent |
elite-status |
Popup → opener | Status (legacy bare snapshot; no BridgeEnvelope wrapper) |
edos-file-event |
Desktop shell → webview (today); future: remote reader parity | EdosFileEventEnvelope (BridgeEnvelope: all sidecars + journal + status, discriminated by sourceType / eventKind) |
message-types-info |
Either | { sendMessageTypes, listenMessageTypes } |
get-message-types |
Either | (triggers info reply) |
open-file:journal |
Opener → popup | (no structured payload in handlers) |
refetch-file:journal |
Opener → popup | — |
poll-file:journal |
Opener → popup | — |
stop-polling:journal |
Opener → popup | — |
open-file:status |
Opener → popup | — |
refetch-file:status |
Opener → popup | — |
poll-file:status |
Opener → popup | — |
stop-polling:status |
Opener → popup | — |
Note: JournalWatcher / StatusWatcher call this.messenger.send(MessageTypeEnum.EliteEvent, event) for journal lines (line 93 in JournalWatcher.ts) — equivalent to sendEliteEvent when the type is allowed.
Same-window listener (Stellar Scan, Credit Account)¶
Files: elite-dangerous-stellar-scan/src/composables/useJournalConnection.ts, elite-dangerous-credit-account/src/composables/useJournalConnection.ts (same IFM pattern; Credit Account ingests ledger events from onEliteEvent / onEdosFileEvent only).
target = window(notwindow.openeror a popup reference).- Listens (IFM allowlist):
EliteEvent,Status,EdosFileEvent. Handlers registered today:onEliteEventandonEdosFileEventonly (useJournalConnection.ts— noonStatusEvent; bareelite-statusis not ingested until a handler is added). - Sends: none (
sendMessageTypesis[]). - Origins:
allowedSenderOriginsfromVITE_ALLOWED_SENDER_ORIGINS(comma-separated) or defaults includinghttps://edjr.howfe.org,https://edss.howfe.org,https://edjev.howfe.org, andhttp://localhost:5173;allowedListenerOrigins: ['*']. - Popup:
openRemoteReader()useswindow.open(VITE_REMOTE_JOURNAL_READER_URL ?? 'https://edjr.howfe.org', …); events are expected to arrive on the samewindowviapostMessagefrom the popup or from the desktop shell’s injected bridge (same-tab / same-window pattern). TODO: Verify EDJR popup → parent routing when opener and listener are not the classic surface-map parent/child pair — compare with fullelite-dangerous-remote-journal-readercheckout.
Embedded mode hides the “Open journal reader” control; use the local journal reader webview or host-driven IFM instead (apps/elite-dangerous-stellar-scan.md).
Parent vs popup construction¶
Popup (remote journal reader)¶
Files: elite-dangerous-remote-journal-reader/ui/src/components/JournalWatchButton.vue, StatusWatchButton.vue.
target = window.opener- Sends:
EliteEvent(journal) orStatus(status file) - Listens:
Open*/Refetch*/Poll*/Stop*for journal or status - Origins:
allowedSenderOrigins: ['*'],allowedListenerOrigins: ['*']in current code — permissive so any opener can control the popup if it sends allowed message types.
Parent (surface map)¶
File: elite-dangerous-surface-map/ui/src/composables/useJournalReader.ts.
target= reference to the popupWindowfromwindow.open('https://edjr.howfe.org', …)- Sends: none of the journal/status command types are registered (
sendMessageTypesis[]); only implicitmessage-types-infohandling from the library constructor - Listens:
EliteEvent,Status - Origins:
allowedSenderOrigins: ['*'],allowedListenerOrigins: ['https://edjr.howfe.org']— incoming messages from any origin are accepted (*); outgoingpostMessageto the popup uses target originhttps://edjr.howfe.org
Security implication: inbound filtering on the parent uses '*' for senders — rely on child origin in practice being the known popup. Tightening to the EDJR origin is a possible hardening step (TODO: Verify if you support multiple embedders).
Sequence: user starts journal feed from map¶
Sequence: journal line parsing (popup)¶
Extending the protocol¶
- Add a new enum value in
inter-frame-messenger/src/index.ts(avoid reusing strings). - Rebuild and publish
@howfe/inter-frame-messenger(or link workspace package). - Update both sender and receiver allowlists (
sendMessageTypes/listenMessageTypes) and handlers. - If payload types are new, extend
@howfe/elite-dangerous-event-types(sidecar blobs +EdosFileEventEnvelope, or journal events) — do not invent ad-hoc shapes only in one app. Do not add per-sidecar IFM outer names such aselite-market; useedos-file-eventand discriminate inside the envelope.
Compatibility¶
- Requires modern
postMessageand (for file picking) File System Access API — Chromium-based browsers / WebView2 align with the assumptions in original-concept.md.