Server (Embedding)
@cuitty/scrape/server is the backend half. It exposes createScrapeServer(config), which returns an object with health(), run(), handleRequest(req), and dispose().
Server Config
createScrapeServer(config) accepts:
| Option | Type | Purpose |
|---|---|---|
bridge | ScrapeAiBridge | Planner, extractor, actor, and healer. Defaults to the mock bridge. |
sessionFactory | () => BrowserSession | Creates one browser session per run. Defaults to the mock session. |
credentials | CredentialProvider | Resolves Safe refs and session storage state. Defaults to the mock provider. |
clock | () => string | Optional deterministic ISO timestamp source. |
idgen | (prefix: string) => string | Optional deterministic ID generator. |
Starting a Server
The current API does not provide server.start(port). Wrap handleRequest(req) with your runtime's HTTP server.
import { createScrapeServer } from "@cuitty/scrape/server";
const scrape = createScrapeServer();
Bun.serve({
port: 4340,
fetch(request) {
return scrape.handleRequest(request);
},
});
console.log("Scrape API on http://127.0.0.1:4340/api/scrape");
In-Process Runs
Use server.run(request, interactionHandler) when you do not need HTTP. This path blocks until completion or until the supplied interaction handler resolves a human-in-the-loop request.
import { createScrapeServer } from "@cuitty/scrape/server";
const server = createScrapeServer();
const result = await server.run(
{ url: "https://example.com", intent: "Confirm the page has content" },
async (request) => ({ id: request.id, outcome: "aborted" }),
);
console.log(result.status, result.answer);
Middleware Shape
handleRequest(req) implements the /api/scrape/* routes. In Bun, Express adapters, Hono, Astro endpoints, or edge runtimes, route matching should forward only the Scrape prefix to this handler.
import { createScrapeServer } from "@cuitty/scrape/server";
const scrape = createScrapeServer();
export async function handleApiRequest(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname.startsWith("/api/scrape/")) {
return scrape.handleRequest(request);
}
return new Response("not found", { status: 404 });
}
Live Server
@cuitty/scrape/live composes the real browser session with the Claude bridge when ANTHROPIC_API_KEY is available. Without a key, it still uses Playwright but falls back to the mock bridge.
import { createLiveScrapeServer } from "@cuitty/scrape/live";
const server = createLiveScrapeServer({
playwright: { headless: true, channel: "chrome" },
forceMockBridge: !process.env.ANTHROPIC_API_KEY,
});
Bun.serve({ port: 4340, fetch: (request) => server.handleRequest(request) });
Interaction Pause and Resume
The async HTTP run manager parks a run in needs-interaction when the engine raises an interaction request. The client or caller responds through POST /api/scrape/runs/:runId/interactions/:interactionId; the server resumes the parked promise and continues the run.