Messaging

Move commands and results between surfaces without repeating Chrome's connection checks and response handling.

Register a handler (background)

Register product-level commands in the background worker so every surface shares one implementation.

import { registerMessageHandler } from "@/shared/messaging";

registerMessageHandler(async (message) => {
  if (message.type === "PING") return { ok: true, data: "pong" };
  if (message.type === "FETCH_DATA") {
    const data = await fetchFromAPI();
    return { ok: true, data };
  }
  return { ok: false, error: "Unsupported message" };
});

Send from popup or side panel

import { sendRuntimeMessage } from "@/shared/messaging";

const response = await sendRuntimeMessage({ type: "PING" });
// { ok: true, data: "pong" }

Send to a content script

These helpers reject restricted pages, inject the content script when needed, and wait until it can receive the message.

import {
  sendTabMessage,
  getActiveInjectableTab,
  ensureContentScriptReady,
} from "@/shared/messaging";

const tab = await getActiveInjectableTab();
await ensureContentScriptReady(tab.id);
const response = await sendTabMessage(tab.id, { type: "EXTRACT_PAGE" });

Generated message types

Keep ChromeShip's runtime messages intact and add product-specific message types alongside them. Define each request and response shape in the generated messaging types file.