Skip to content

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.

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 validated with isEliteEvent / isStatus from @howfe/elite-dangerous-event-types.

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 lines 104–113).

MessageTypeEnum

Defined in inter-frame-messenger/src/index.ts:

Value Direction (typical) Payload
elite-event Popup → opener EliteEvent
elite-status Popup → opener Status
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.

Parent vs popup construction

Files: elite-dangerous-remote-journal-reader/ui/src/components/JournalWatchButton.vue, StatusWatchButton.vue.

  • target = window.opener
  • Sends: EliteEvent (journal) or Status (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 popup Window from window.open('https://edjr.howfe.org', …)
  • Sends: none of the journal/status command types are registered (sendMessageTypes is []); only implicit message-types-info handling from the library constructor
  • Listens: EliteEvent, Status
  • Origins: allowedSenderOrigins: ['*'], allowedListenerOrigins: ['https://edjr.howfe.org'] — incoming messages from any origin are accepted (*); outgoing postMessage to the popup uses target origin https://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

sequenceDiagram participant User participant Map as Surface map participant Pop as Journal reader popup participant FS as File System Access API User->>Map: Click start journal reader Map->>Pop: window.open(edjr) Map->>Map: new InterFrameMessenger(popup, listen=elite-event,status) User->>Pop: Open journal / status file Pop->>FS: read file loop poll ~1s Pop->>Pop: parse lines / JSON Pop->>Map: postMessage elite-event / elite-status Map->>Map: onEliteEvent / onStatus callbacks end

Sequence: journal line parsing (popup)

sequenceDiagram participant JW as JournalWatcher participant FS as File handle participant IFM as InterFrameMessenger JW->>FS: updateData / read text JW->>JW: split lines, JSON.parse JW->>JW: isEliteEvent + dedupe by line JW->>IFM: send(elite-event, payload) IFM->>IFM: opener.postMessage({event, payload})

Extending the protocol

  1. Add a new enum value in inter-frame-messenger/src/index.ts (avoid reusing strings).
  2. Rebuild and publish @howfe/inter-frame-messenger (or link workspace package).
  3. Update both sender and receiver allowlists (sendMessageTypes / listenMessageTypes) and handlers.
  4. If payload types are new, extend @howfe/elite-dangerous-event-types (or a separate package) — do not invent ad-hoc shapes only in one app.

Compatibility

  • Requires modern postMessage and (for file picking) File System Access API — Chromium-based browsers / WebView2 align with the assumptions in original-concept.md.