LAB429/ Cheetah product page ↗

Cheetah / Cheetah documentation

Prepare browser parser capture

The browser runtime knows when parser capture belongs in the command lifecycle. A Manifest V3 extension must still package two platform pieces: a page content script that can serialize the target document and an offscreen document that runs the parser without depending on the service worker remaining alive.

This task makes an existing browser client capable of Imprint parser capture. It does not register a parser, grant access to every website, or prove the complete server-to-history result path.

Before you begin

Start from an extension that already:

  • creates and starts @cheetah/browser with createBrowserRuntime();
  • bundles its service worker rather than loading TypeScript directly;
  • connects successfully to the intended Cheetah host;
  • has a build where you can add one content-script entry and one offscreen entry;
  • has an explicit list of page origins the product may inspect.

The repository's most minimal browser example may package only its service worker. Source files existing in the workspace do not make them part of the loadable extension.

Add the page-side runtime

Create a content-script entry:

import { createContentScriptRuntime } from '@cheetah/browser';

const contentRuntime = createContentScriptRuntime({
  debug: false,
  logPrefix: '[Product page runtime]',
});

contentRuntime.start();

Bundle it as a normal content script, for example content_script.js. It handles the service worker's page requests, including the serialized DOM used by the parser runner. Product- specific page actions should remain separately registered and limited to pages where they are intended.

Add the offscreen runner

Create a small TypeScript entry:

import '@cheetah/browser/parser/offscreen-entry';

Bundle it as an ES module such as offscreen_parser.js, then load it from an HTML file copied to the extension output:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Cheetah parser runner</title>
  </head>
  <body>
    <script type="module" src="offscreen_parser.js"></script>
  </body>
</html>

Keep the filename offscreen.html unless the runtime receives a differently configured OffscreenParserClient. The default browser composition creates the document lazily for the first parser job, reuses it for queued work, and closes it after its idle interval. A timeout or cancellation closes the interrupted document before later work recreates it.

Grant the smallest browser boundary

Add the offscreen permission, the built content script, and only the origins the product owns or intentionally supports:

{
  "permissions": ["tabs", "storage", "offscreen"],
  "host_permissions": ["https://app.example.com/*"],
  "content_scripts": [
    {
      "matches": ["https://app.example.com/*"],
      "js": ["content_script.js"],
      "run_at": "document_idle"
    }
  ]
}

Replace the example origin. Parser capture is not a reason to copy <all_urls> into a real product. Chrome-protected pages and pages outside the declared matches cannot be serialized; that is a capability boundary, not a transient parser error.

Use the normal runtime composition

When the defaults fit, no additional parser object is required in the service worker. createBrowserRuntime() composes:

  • a parser-definition cache backed by chrome.storage.local;
  • an offscreen Imprint runner;
  • a browser capture provider that obtains one DOM snapshot and passes it to requested parsers;
  • a fetch-based resolver for supported offloaded command parameters and parser definitions.

The cache can survive service-worker restarts. The runtime must still reconnect and recreate its current runtime identity after Chrome restarts that worker.

Applications can replace these interfaces, but an override becomes responsible for the same preflight, cancellation, result, and security contracts.

Verify the built extension

Inspect the actual loadable output after the existing build. It should contain:

  • the manifest with offscreen and the intended page matches;
  • the service-worker bundle;
  • content_script.js;
  • offscreen.html;
  • offscreen_parser.js.

Load that output as an unpacked extension. On one permitted page, run an ordinary page-side action such as get_page_info. That proves the service worker can reach the content-script runtime. Then register a trusted parser definition, issue an applied command with required parser capture, and read the retained terminal result. The final check should show the named result under payload._capture.parsers with the exact engine, parser ID, and version.

Follow failures to their boundary

  • chrome.offscreen is not available usually means the manifest lacks the permission or the browser lacks the API.
  • A missing offscreen.html or parser bundle means the build did not copy or emit the files.
  • A content-script connection error means the target did not receive the bundle, the match pattern excludes it, or Chrome protects that page.
  • A working page action followed by capture_parser_runner_unavailable points to the offscreen document or listener.
  • capture_parser_missing during preflight means the exact definition was not cached or delivered; it should be resolved before diagnosing the page extraction.

Parser registry and definitions

Post-command capture