Expose ExtractorSession for Playwright/camoufox-js so Node automations can import context dumps instead of shelling out to the Python package. Same fixture as the Python tests; wired into Makefile and Gitea CI.
context-extractor (JS/TS automation)
Node/Playwright twin of the Python automation/ package — same
extension/core/dom.js + extension/core/prompt.js (via symlinks in
src/js/), same output shape, same test fixture. Use this one from Node
tooling (Playwright, playwright-core, or camoufox-js)
instead of shelling out to Python.
One ExtractorSession class covers both sync/async use cases — Node's
Playwright API is async-only to begin with, so there's no sync/async split
like the Python package's ExtractorSession / AsyncExtractorSession.
Install
cd automation-js
npm install
npm run build
Not published to a registry yet — consume it from this checkout via a
relative file: dependency, or copy dist/ + dist/js/ into a consumer.
Use
import { chromium } from 'playwright-core'; // or 'playwright', or camoufox-js
import { ExtractorSession } from 'context-extractor'; // this package
const browser = await chromium.launch();
const page = await browser.newPage();
const session = new ExtractorSession(page); // attach BEFORE navigating
await page.goto('https://example.com', { waitUntil: 'networkidle' });
console.log(await session.buildAiPrompt()); // or session.extractMarkdown('#main')
console.log(session.getStore()); // { console, errors, network }
With camoufox-js — same idea,
launchServer/launchOptions differ but the returned page is a normal
Playwright Page:
import { launchOptions } from 'camoufox-js';
import { firefox } from 'playwright-core';
import { ExtractorSession } from 'context-extractor';
const browser = await firefox.launch(await launchOptions({ headless: false }));
const page = await browser.newPage();
const session = new ExtractorSession(page);
Why this exists (vs. shelling out to the Python package)
If your automation is already Node/Playwright (Cursor-driven scripts, a
camoufox-js session, a Playwright test suite), the Python package meant
spawning a subprocess and shipping JSON across a process boundary just to get
a markdown dump. This package removes that boundary — same core JS, same
output, but a normal import + await in the same process/event loop as the
rest of your automation.
Tests
npm test
Runs against a real headless Chromium (playwright-core) loading the shared
fixture at ../automation/tests/fixtures/sample.html — the exact same file
the Python automation/tests/test_session.py suite uses, so a
markdown-formatting regression can't silently diverge between the two
automation layers.
Notes
extractMarkdown(selector?)returns{ url, title, ts, selector, markdown }.buildAiPrompt(selector?, maxChars?)wraps that in the same# Page Context/## Page Content/ errors / console / network prompt format as the extension's Copy button and the Python package.getStore()/clear(which?)expose the same bounded ring buffers (console,errors,network, capped at 200 entries each) as the Python_Store.- Call
session.detach()if you keep a page open long after you're done capturing and want to stop accumulating entries.